#-*- coding: utf-8 -*- # Copyright 2008-2010 Mir Calculate. 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 sys import re import ldap import cStringIO, StringIO from ldif import LDIFParser, LDIFWriter import cl_base import cl_profile import cl_utils2 import cl_utils # Для подсчета символов import termios, fcntl, struct # Ввод pwd import getpass # Статистика файла import stat import types # Для ввода символа import tty # Работа со временем import time import datetime # Создание временных файлов import tempfile # Вывод в строку ввода import readline # Пути в XML документе from xml import xpath # Для 32 битного целого (генерация серийного номера DNS зоны) import ctypes Version = "calculate-server 2.1.18" tr = cl_base.lang() tr.setLanguage(sys.modules[__name__]) pcs = cl_utils.prettyColumnStr class report: """Класс для выдачи данных в табличном виде""" def __init__(self, title, headerList, dataList): # Заголовок self.title = title # Cписок элементов первой строки таблицы self.headerList = headerList # Список строк (каждая строка - список элементов) self.dataList = dataList # Список ширин колонок self.columnsWidth = self.getColumsnWidth() def getColumsnWidth(self): """Находит максимальную ширину каждой колонки результат список ширин колонок """ columnsWidth = [] lenCol = 0 for s in self.headerList: lenCol += 1 columnsWidth.append(len(cl_utils._toUNICODE(s))) maxLenCol = lenCol # Вычисляем максимальное количество столбцов for s in self.dataList: lenS = len(s) if maxLenCol < lenS: maxLenCol = lenS if maxLenCol > lenCol: appCol = maxLenCol - lenCol # Добавляем элементы в список ширин for i in range(appCol): columnsWidth.append(0) # Вычисляем ширину столбцов for e in self.dataList: i = 0 for s in e: lenS = len(cl_utils._toUNICODE(s)) if columnsWidth[i] < lenS: columnsWidth[i] = lenS i += 1 return columnsWidth def createFormatStr(self, listStr): """Создает список (текст, ширина ...)""" strList = [] lenStr = len(listStr) for i in range(len(self.columnsWidth)): if lenStr > i: strList.append(listStr[i]) else: strList.append("") strList.append(self.columnsWidth[i]) return strList def printReport(self): """Напечатать данные в табличном виде""" print self.title listStrSep = [] for lenCol in self.columnsWidth: listStrSep.append("-"*lenCol) printData = "" printData += cl_utils.columnStr(*self.createFormatStr(listStrSep)) printData += cl_utils.columnStr(*self.createFormatStr(self.headerList)) printData += cl_utils.columnStr(*self.createFormatStr(listStrSep)) for s in self.dataList: printData += cl_utils.columnStr(*self.createFormatStr(s)) printData += cl_utils.columnStr(*self.createFormatStr(listStrSep)) if printData[-1] == "\n": printData = printData[:-1] lines = printData.splitlines() lenCols = map(lambda x: len(x), lines[0].strip().split(" ")) convLines = [] lenLines = len(lines) for i in range(lenLines): char = " | " if i == 0 or i == 2 or i == lenLines-1: char ="-+-" convLines.append(self._insertStrChar(lines[i], lenCols, char)) print "\n".join(convLines) print "(%s %s)"%(len(self.dataList), _("rows")) return True def _insertStrChar(self, line, lenCols, char): """Вставляет несколько символов char в указанные позиции сначала строки будет вставлено char[1:] в конце строки char[:-1] """ lineUnicode = cl_utils._toUNICODE(line) prevPos = 0 convLine = char[1:] lenLenCols = len(lenCols) for i in range(lenLenCols): pos = lenCols[i] + prevPos if i == lenLenCols-1: insertChar = char[:-1] else: insertChar = char convLine += lineUnicode[prevPos:pos] + insertChar prevPos = pos + 1 return convLine.encode("UTF-8") def adminConnectLdap(fun): """Cоединение с LDAP администратором сервиса (декоратор) соединение с LDAP и проверка установки необходимых переменных """ def ret (self, *arg, **argv): flagError = False if not self.clVars: self.createClVars() if not self.ldapObj: if not self.getLdapObjInFile(): flagError = True if not self.baseDN: if self.clVars.defined("ld_base_dn"): self.baseDN = self.clVars.Get("ld_base_dn") if not self.baseDN: self.printERROR (_('Not found LDAP base DN')) if flagError: return False else: return fun(self, *arg , **argv) return ret class iniLdapParser(cl_base.iniParser): """Класс для работы c ini-файлом ldap""" def __init__(self): # название ini файла self.nameIniFile = "/var/lib/calculate/calculate.ldap" cl_base.iniParser.__init__(self, self.nameIniFile) # права создаваемого ini-файла self.setMode(0600) pathIniFile = os.path.split(self.nameIniFile)[0] if not os.path.exists(pathIniFile): os.makedirs(pathIniFile) class addLdif(LDIFParser): """Класс необходимый для добавления записей в LDAP""" def __init__(self, strInput,ldapCon): FD = cStringIO.StringIO(strInput) LDIFParser.__init__(self, FD) self.ldapCon = ldapCon def handle(self, dn, entry): self.ldapCon.add_s(dn, entry.items()) class ldapFunction(cl_utils2.ldapFun): '''Объект для работы с LDAP сервером''' def __init__(self, dnUser, password): cl_utils2.ldapFun.__init__(self, dnUser, password) def ldapAdd(self, strLdif): """Добавляем строку содержащую ldif в LDAP Если данные существуют - ошибка """ if self.conLdap: try: # Записываем параметры из ldif файла в LDAP сервер parser = addLdif(strLdif,self.conLdap) parser.parse() except ldap.LDAPError, e: self.setError(e[0]['desc']) return False except: self.setError("Error in ldif file") return False return True else: self.setError(_("No connect to LDAP server")) return False # Импортированные классы в cl_ldap # Запись ошибок imp_cl_err = cl_profile._error # Работа с XML imp_cl_xml = cl_profile.xmlShare # Обработка параметров командной строки imp_cl_help = cl_utils2.cl_help # Форматированный вывод imp_cl_smcon = cl_utils2.cl_smartcon class prnServ: """Класс хранения метода печати названия сервиса""" def printNameService(self, service): """Выдает имя сервиса для печати""" if service in ["ldap", "dns", "dhcp", "ftp"]: ret = service.upper() else: if service=="mail_relay": ret = "Mail" else: ret = service.capitalize() return ret class shareIP: """Класс хранения методов работы с ip""" def getNet(self, ip, mask): """По ip и маске получаем сеть""" octetsMult = (0x1, 0x100, 0x10000, 0x1000000) octetsIp = map(lambda x: int(x), ip.split(".")) octetsMask = map(lambda x: int(x), mask.split(".")) ipNumb = 0 for i in octetsMult: ipNumb += octetsIp.pop()*i maskNumb = 0 for i in octetsMult: maskNumb += octetsMask.pop()*i startIpNumber = maskNumb&ipNumb x = startIpNumber nMask = lambda y: len(filter(lambda x: y >> x &1 ,range(32))) return "%s.%s.%s.%s/%s"\ %(x>>24, x>>16&255, x>>8&255, x&255, nMask(maskNumb)) def getNumberIP(self, ip): """По строке ip получаем число (номер ip)""" octetsIp = map(lambda x: int(x), ip.split(".")) octetsMult = (0x1, 0x100, 0x10000, 0x1000000) ipNumb = 0 for i in octetsMult: ipNumb += octetsIp.pop()*i return ipNumb def getNumberNetmask(self, netmask): """По числу 16 24 и.т д получаем номер сетевой маски""" maxMaskNumb = 0xffffffff netmask = int(netmask) shift = 32-netmask maskNumb = maxMaskNumb >> shift << shift return maskNumb def getMinAndMaxIpNumb(self, net, maskIp=""): """Минимальное и максимальное значение номера ip""" ip, spl, netmask = net.partition("/") maxMaskNumb = 0xffffffff if maskIp: maskNumb = self.getNumberIP(maskIp) else: maskNumb = self.getNumberNetmask(netmask) ipNumb = self.getNumberIP(ip) startIpNumber = maskNumb&ipNumb endIpNumber = ipNumb|(maskNumb^maxMaskNumb) return startIpNumber, endIpNumber def getIPinNumber(self, n): """Из номера получаем ip""" return "%s.%s.%s.%s" %(n >> 24, n >> 16 & 255, n >> 8 & 255, n & 255) class shareLdap(imp_cl_err, imp_cl_xml, imp_cl_help, imp_cl_smcon, prnServ): """Класс хранения общих методов для всех сервисов""" # DN сервисов относительно базового ServicesDN = "ou=Services" # Сервисы и демоны servicesDaemons = {"ldap":["slapd"], "unix":["slapd"], "samba":["samba"], "mail":["postfix","dovecot"], "mail_relay":["postfix"], "jabber":["ejabberd"], "ftp":["proftpd"], "proxy":["squid"], "dns":["named"], "dhcp":["dhcpd"]} def __init__(self): # Переменная объект Vars self.clVars = False # Переменная объект ldapFunction self.ldapObj = False # Переменная соединение с LDAP сервером self.conLdap = False # Базовый DN LDAP сервера self.baseDN = False # Статические группы self.staticGroups = {\ 'client':self.addInfoGroup('client', '900', 'Client group', '2801', '2'), 'Domain Admins':self.addInfoGroup('Domain Admins', '512', 'Domain Administrators', '512', '2'), 'Domain Users':self.addInfoGroup('Domain Users', '513', 'Domain Users', '513', '2'), 'Domain Guests':self.addInfoGroup('Domain Guests', '514', 'Domain Guests Users', '514', '2'), 'Domain Computers':self.addInfoGroup('Domain Computers', '515', 'Domain Computers accounts', '515', '2'), 'Administrators':self.addInfoGroup('Administrators', '544', 'Domain Members can fully \ administer the computer/sambaDomainName', '544', '5', "S-1-5-32-544"), 'Account Operators':self.addInfoGroup('Account Operators', '548', 'Domain Users to manipulate \ users accounts', '548', '5', "S-1-5-32-548"), 'System Operators':self.addInfoGroup('System Operators', '549', 'Domain System Operators', '549', '5', "S-1-5-32-549"), 'Print Operators':self.addInfoGroup('Print Operators', '550', 'Domain Print Operators', '550', '5', "S-1-5-32-550"), 'Backup Operators':self.addInfoGroup('Backup Operators', '551', 'Domain Members can bypass \ file security to back up files', '551', '5', "S-1-5-32-551"), 'Replicators':self.addInfoGroup('Replicators', '552', 'Domain Supports file replication \ in a sambaDomainName', '552', '5', "S-1-5-32-552"), } # Статические пользователи self.staticUsers = {\ 'client':self.addInfoUser('client', '900', '900', 'Client samba user'), 'admin':self.addInfoUser('admin', '901', '544', 'Admin samba user')} def getUserUidAndGid(self, userName, groupName=""): """Находит в системе uid и gid пользователя userName - имя пользователя и имя группы пользователя """ if not groupName: groupName = userName import pwd try: uid = pwd.getpwnam(userName)[2] except: self.printERROR(_("Can not found user %s in this system")%userName) return () try: import grp gid = grp.getgrnam(groupName)[2] except: self.printERROR(_("Can not found user %s in this system")%groupName) return () return (uid, gid) def genSleep(self): """Генератор задержек""" timeSleep = (0.2, 0.4, 0.8) for t in timeSleep: time.sleep(t) yield(t) def reloadDefaultVar(self, nameVar): """При получениии значения переменной снова вызывается метод заполнения переменной""" self.clVars.Set(nameVar,"",True) self.clVars.__getattribute__(nameVar).countFill = 0 self.clVars.__getattribute__(nameVar).fillStart = True return True def addInfoGroup(self, name, gid, comment, rid="", type="", sid=""): """Добавляем информацию о группе""" class group(): """Информация о группе""" name = "" gid = "" comment = "" rid = "" type = "" sid = "" gr = group() gr.name = name gr.gid = gid gr.comment = comment gr.rid = rid gr.type = type gr.sid = sid return gr def addInfoUser(self, name, uid, gid, comment): """Добавляем информацию о пользователе""" class user(): """Информация о пользователе""" name = "" uid = "" gid = "" comment = "" us = user() us.name = name us.uid = uid us.gid = gid us.comment = comment return us def connectToLDAP(self, adminDn, adminPw): """Подключаемся к LDAP - для внешних программ запускающихся не от root """ ldapObj = ldapFunction(adminDn, adminPw) # Генератор задержек wait = self.genSleep() while ldapObj.getError(): try: # Задержка wait.next() except StopIteration: break # Очистка ошибки cl_profile._error.error = [] ldapObj = ldapFunction(adminDn, adminPw) if ldapObj.getError(): # Удаляем одинаковые ошибки listError = [] for e in ldapObj.error: if not e in listError: listError.append(e) cl_profile._error.error = listError self.printERROR (_("LDAP connect error") + ": " +\ ldapObj.getError().strip()) return False # Устанавливаем у объекта соединение и объект LDAP функций self.ldapObj = ldapObj self.conLdap = ldapObj.conLdap return True def shortToFullName(self, listNames, domain): """Из списка коротких имен получаем cписок полных имен К коротким именам добавляем домен, длинные выдаем как есть """ listFillNames = [] for name in listNames: if "." in name: listFillNames.append(name) else: listFillNames.append("%s.%s" %(name,domain)) return listFillNames def getServiceSetup(self): """находит установленные сервисы Выдаем список [установленные сервисы] """ # инсталированнные сервисы servInstalled = [] # доступные сервисы services = ('ldap', 'unix', 'samba', 'mail', 'jabber', 'ftp', 'proxy', 'dns', 'dhcp') for serv in services: if self.clVars.Get("sr_%s_set"%serv) == "on": servInstalled.append(serv) return servInstalled def restorePathDelUser(self,userName,destDir,relDir,message,unixObj=False): """Восстанавливает директорию удаленного пользователя""" removeDir = False flagError = False resRestore = self.restoreDelUser(userName, relDir, destDir, message,unixObj) # Если ошибка то выходим if not resRestore: flagError = True # Флаг создания директории профиля пользователя createDir = destDir term = "" if resRestore == True: term = message if not flagError and type(resRestore) == types.TupleType: # Если cansel if resRestore[0] == "Cancel": # Удаляем пользователя flagError = True term = None # Если No elif resRestore[0] == "No": if not self.removeDir(resRestore[1]): flagError = True if not flagError: removeDir = resRestore[1] term = False elif resRestore[0] == "Yes": createDir = False removeDir = resRestore[1] term = True if flagError or term == "": return False else: return (term, createDir, removeDir) @adminConnectLdap def restoreDelUser(self,userName,service,srcDir,message,unixObj=False): """Возвращаем данные удаленного пользователя""" # Ищем Unix пользователя if unixObj: servUnixObj = unixObj else: servUnixObj = self.servUnixObj searchUnixUser = servUnixObj.searchUnixUser(userName) # id пользователя strUid = "" if searchUnixUser: strUid = searchUnixUser[0][0][1]['uidNumber'][0] else: resPasswd = servUnixObj.searchPasswdUser(userName) if resPasswd: strUid = resPasswd.split(":")[2] if strUid: delBackDir =\ os.path.join(self.clVars.Get("sr_deleted_path"), "%s-%s"%(userName,strUid), service) if strUid and os.path.exists(delBackDir) and os.listdir(delBackDir): if message == None or type(message) == types.BooleanType: dialogRes = message else: dialogRes = self.dialogYesNo(message) if dialogRes and dialogRes == True: try: self.copyDir(srcDir, delBackDir) except: self.printERROR(_("Not restore user data in dir %s")\ %srcDir) return False self.printSUCCESS(_("Restore user data in dir %s")\ %srcDir) return "Yes", delBackDir elif dialogRes == False: return "No", delBackDir elif dialogRes == None: return "Cancel", delBackDir return True @adminConnectLdap def backupDelUser(self, userName, service, srcDir, unixObj=False): """Сохраняем данные удаляемого пользователя""" # Ищем Unix пользователя if unixObj: servUnixObj = unixObj else: servUnixObj = self.servUnixObj searchUnixUser = servUnixObj.searchUnixUser(userName) # id пользователя strUid = "" if searchUnixUser: strUid = searchUnixUser[0][0][1]['uidNumber'][0] if strUid: delBackDir =\ os.path.join(self.clVars.Get("sr_deleted_path"), "%s-%s"%(userName,strUid), service) if os.path.exists(delBackDir) and os.listdir(delBackDir): self.printERROR(_("Found deleted user data dir %s")\ %delBackDir) self.printERROR(_("Not created deleted user data dir %s")\ %delBackDir) return False else: delBackDir =\ os.path.join(self.clVars.Get("sr_deleted_path"), "%s"%(userName), service) i = 0 while os.path.exists(delBackDir): i += 1 delBackDir =\ os.path.join(self.clVars.Get("sr_deleted_path"), "%s_%s"%(userName,i), service) # Cоздаем директорию хранения удаленных пользователей if not os.path.exists(self.clVars.Get("sr_deleted_path")): os.makedirs(self.clVars.Get("sr_deleted_path")) #Делаем сохранение директории try: self.copyDir(delBackDir,srcDir) except: self.printERROR(_("Can not copy deleted user data in dir %s")\ %delBackDir) return False self.printSUCCESS(_("Created deleted user data dir %s")\ %delBackDir) return True def stringIsJpeg(self, string): """Определяет является ли строка jpeg изображением""" if len(string)<8: return False FD = cStringIO.StringIO(string) isJpeg = False FD.seek(0, 0) (firstByte, secondByte) = FD.read(2) if (ord(firstByte) == 0xff and ord(secondByte) == 0xd8): (firstByte, secondByte) = FD.read(2) if (ord(firstByte) == 0xff and ord(secondByte) == 0xe0): isJpeg = True return isJpeg def _getDefaultRunlevelDaemons(self): """Получаем всех демонов в default уровне""" execStr = "rc-update show" textLine = self.execProg(execStr, None, False) if textLine == False: self.printERROR(_("ERROR") + ": " + execStr) return False else: splLines = filter(lambda x: len(x)==2 and "default" in x[1],\ map(lambda x: x.split("|"),textLine)) splLines = map(lambda x: x[0].strip(), splLines) return splLines def setDaemonAutostart(self, daemon): """Прописывает демона в автозагрузку""" if daemon in self._getDefaultRunlevelDaemons(): return True execStr = "rc-update add %s default" %daemon textLine = self.execProg(execStr) if textLine == False: self.printERROR(_("ERROR") + ": " + execStr) self.printERROR(_("Can not add '%s' at default runlevel")%daemon) return False else: return True def delDaemonAutostart(self, daemon): """Удаляет демона из автозагрузки""" if not (daemon in self._getDefaultRunlevelDaemons()): return True self._getDefaultRunlevelDaemons() execStr = "rc-update del %s default" %daemon textLine = self.execProg(execStr) if textLine == False: self.printERROR(_("ERROR") + ": " + execStr) self.printERROR(_("Can not deleted '%s' from default runlevel")\ %daemon) return False else: return True def runLdapServer(self): """Запускает LDAP сервер""" textLines = self.execProg("/etc/init.d/slapd start") if textLines == False: self.printNotOK(_("Starting LDAP")+ " ...") return False else: return True def restartLdapServer(self): """Запускает LDAP сервер""" textLines = self.execProg("/etc/init.d/slapd restart") if textLines == False: self.printNotOK(_("Restarting LDAP")+ " ...") return False else: return True def stopLdapServer(self): """Останавливает LDAP сервер""" textLines = self.execProg("/etc/init.d/slapd stop") if textLines == False: self.printNotOK(_("Stopping LDAP")+ " ...") return False else: return True def getALLServices(self): """Получаем все сервисы которые описаны в профилях""" # путь к директории профилей profilePath = self.clVars.Get("cl_profile_path")[0] data = os.listdir(profilePath) service = [] for fileData in data: if os.path.isdir(os.path.join(profilePath, fileData)): service.append(fileData) if service: # После добавления сервисов в класс необходимо удалить # apache и backup if 'backup' in service: service.remove('backup') if 'apache' in service: service.remove('apache') return service def applyProfilesFromService(self, service, verbose=False): """Применяем профили для данного сервиса""" # Cоздаем объект профиль устанавливая директорию # service для файлов профилей clProf = cl_profile.profile(self.clVars,service) # Объединяем профили data = clProf.applyProfiles() if clProf.getError(): self.printERROR(clProf.getError()) return False else: if verbose and type(data) == types.TupleType: dirs, files = data return files return True def searchService(self): """Поиск DN сервиса""" name, value = self.relServDN.split('=') resSearch = self.searchLdapDN(value, self.ServicesDN, name) return resSearch def delServicesAutostart(self, servInstalled): """Удаляет из автозагрузки сервисы Входные данные - список названий сервисов """ flagError = False delDaemons = [] for service in servInstalled: if not service in self.servicesDaemons.keys(): self.printERROR(_("Not supported service '%s'")%service) self.printERROR(\ _("Can not deleted service from default runlevel")) flagError = True break for daemon in self.servicesDaemons[service]: if not daemon in delDaemons: delDaemons.append(daemon) if not self.delDaemonAutostart(daemon): flagError = True break if flagError: break if flagError: return False else: return True def startDaemons(self, service, daemons, printSuccess=True): """Стартует демонов""" flagError = False for daemon in daemons: if not self.getRunDaemons([daemon]): textLines = self.execProg("/etc/init.d/%s start" %(daemon)) if textLines == False: self.printERROR( _("Daemon %s was not started") %daemon) flagError = True break prnService = self.printNameService(service) if flagError: self.printNotOK(_("Starting") + " " + prnService + " " +\ _("service") + " ...") return False else: if printSuccess: self.printOK(_("Starting") + " " + prnService + " "+\ _("service") + " ...") return True def startServices(self, servInstalled, printSuccess=True): """Запускает все сервисы поданные на вход этому методу Также прописывает в автозагрузку Входные даннные - список названий сервисов """ addDaemons = [] if 'ldap' in servInstalled or 'unix' in servInstalled: if not self.startDaemons('ldap',['slapd'], printSuccess): return False # Устанавливаем автозапуск демона if not self.setDaemonAutostart("slapd"): return False addDaemons.append("slapd") flagError = False for service in servInstalled: if not service in self.servicesDaemons.keys(): self.printERROR(_("Can not supported service '%s'")%service) self.printERROR(_("Can not add service at default runlevel")) flagError = True break for daemon in self.servicesDaemons[service]: if not daemon in addDaemons: addDaemons.append(daemon) if not self.startDaemons(service, [daemon], printSuccess): flagError = True break if not self.setDaemonAutostart(daemon): flagError = True break if flagError: break if flagError: return False else: return True def stopServices(self, servInstalled): """Останавливает все сервисы поданные на вход этому методу Входные даннные - список названий сервисов """ addDaemons = [] if 'ldap' in servInstalled or 'unix' in servInstalled: addDaemons.append("slapd") flagError = False for service in servInstalled: if not service in self.servicesDaemons.keys(): self.printERROR(_("Can not supported service '%s'")%service) self.printERROR(_("Can not stop service")) flagError = True break # Название сервиса для вывода на экран servicePrn = self.printNameService(service) for daemon in self.servicesDaemons[service]: if not daemon in addDaemons: addDaemons.append(daemon) # Если демон запущен и не squid то останавливаем его if not daemon in ["squid"] and self.getRunDaemons([daemon]): ret = self.execProg("/etc/init.d/%s stop"%daemon) if ret == False: self.printERROR(servicePrn + " " +\ _("service is not stopped")) flagError = True break # Удаляем процессы ejabberd if daemon == "ejabberd": strCmd = "ps ax" listProcess = self.execProg(strCmd,False,False) if listProcess == False: self.printERROR(_('Can not execute "%s"')%strCmd) return False killPid = [] for process in listProcess: if "erlang" in process: killPid.append(process.split(" ")[0]) if killPid and " ".join(killPid).strip(): textLine=self.execProg("kill %s" %" ".join(killPid)) if textLine == False: self.printERROR(_("Can not 'kill %s'")\ %" ".join(killPid)) flagError = True break elif daemon == "squid" and self.getRunDaemons(["squid"]): errStopProxy = False # Создаем 2 процесса pid = os.fork() tic = 0 if pid: message = _("Waiting for squid to shutdown") + " " self.printSUCCESS(message, 0, False) perm = [0] offset = 0 while not perm[0]: perm = os.waitpid(pid, os.WNOHANG) if perm[1]: errStopProxy = True break time.sleep(0.1) tic += 1 if tic>=15: sys.stdout.flush() sys.stdout.write(".") offset += 1 tic = 0 if errStopProxy: self.printOnlyNotOK(" ",\ self.lenString(message)+\ offset+3) else: self.printOnlyOK(" ",self.lenString(message)+\ offset+3) else: sys.stdout.flush() if os.system("/etc/init.d/squid stop &>/dev/null"): sys.exit(1) else: sys.exit(0) # Если ошибка при остановке proxy сервера if errStopProxy: self.printERROR(servicePrn + " " +\ _("service is not stopped")) flagError = True break if flagError: break if not flagError and "slapd" in addDaemons: if self.getRunService('ldap'): textLines = self.execProg("/etc/init.d/slapd stop") if textLines == False: self.printERROR("LDAP" + " " +\ _("service is not stopped")) flagError = True if flagError: return False else: return True def getUserPassword(self, options, optDialog, optStdIn, pwDialog=False): """Получить пароль у пользователя options - полученные опции командной строки optDialog - опция командной строки для вывода диалога для получения пароля optStdIn - опция командной строки для получения пароля из стандартного ввода (stdin) pwDialog - структура для вывода приглашения в режиме диалога """ userPwd = "" if optStdIn and options.has_key(optStdIn): pwdA = sys.stdin.readline().rstrip() pwdB = pwdA elif optDialog and options.has_key(optDialog): if not pwDialog: pwDialog = [_("New password"), _("Retype new password")] pwdA = getpass.getpass(pwDialog[0]+":") pwdB = getpass.getpass(pwDialog[1]+":") if (optStdIn and options.has_key(optStdIn)) or\ (optDialog and options.has_key(optDialog)): if not pwdA or not (pwdA == pwdB): self.printERROR (_("ERROR") + ": " +\ _("password incorrect")+ ": " + _("try again")) return False userPwd = pwdA return userPwd def getRunDaemons(self, daemons, printError=False): """Проверка, запущены ли демоны""" baseDir = "/var/run" runDaemons = {} flagBaselayoutDir = False for daemon in daemons: # Проверка на запуск демона postfix if daemon == 'postfix': flagRun = False strCmd = "ps ax" listProcess = self.execProg(strCmd, False, False) if not listProcess: self.printERROR(_('Can not execute "%s"')%strCmd) return False for process in listProcess: if "postfix/master" in process: flagRun = True break if flagRun: runDaemons['postfix'] = True else: runDaemons['postfix'] = False continue addDirDict = {"slapd":("openldap","slapd.pid"), "dovecot":("dovecot","master.pid"), "proftpd":("","proftpd.pid"), "squid":("","squid.pid"), "sortmilter":("","sortmilter.pid")} baselayoutDir = "/var/lib/init.d/daemons" if not flagBaselayoutDir: if os.path.exists(baselayoutDir): flagBaselayoutDir = True if flagBaselayoutDir: addDirDict["ejabberd"] = (baselayoutDir,"ejabberd") addDirDict["samba"] = (baselayoutDir,"samba") addDirDict["named"] = (baselayoutDir,"named") addDirDict["dhcpd"] = (baselayoutDir,"dhcpd") elif daemon in ["ejabberd", "samba", "named", "dhcpd"]: if not os.system("/lib/rc/bin/service_started %s" %daemon): runDaemons[daemon] = True else: runDaemons[daemon] = False continue if addDirDict[daemon][0][:1] == "/": pidDir = addDirDict[daemon][0] else: pidDir = os.path.join(baseDir,addDirDict[daemon][0]) if os.access(pidDir, os.F_OK) and os.listdir(pidDir) and\ os.path.exists(os.path.join(pidDir,addDirDict[daemon][1])): runDaemons[daemon] = True else: runDaemons[daemon] = False if printError: for daemon in daemons: if not runDaemons[daemon]: self.printERROR(_("Daemon %s is not started") %daemon) if False in runDaemons.values(): return False else: return True def getHashPasswd(self, password, crypt): """Хеш пароля используя slappasswd""" if not crypt: self.printERROR(_("ERROR") + " getHashPasswd: " +\ _("crypto algoritm empty")) return False cryptStr = "{%s}"%crypt.upper() lenCryptStr = len(cryptStr) pwd = re.sub("(\W)", r"\\\1", password) pwdHash = self.execProg("slappasswd -s %s -h %s" %(pwd,cryptStr)) if pwdHash and len(pwdHash)>lenCryptStr and\ pwdHash[:lenCryptStr] == cryptStr: return pwdHash self.printERROR(_("ERROR") + " getHashPasswd: " +\ _("create crypto password")) return False def getRunService(self, nameService, printError=False): """Проверка, запущен ли сервис с данным именем""" flagError = False if not nameService in self.servicesDaemons.keys(): self.printERROR(_("Can not supported service '%s'")%nameService) self.printERROR(_("Can not check run service")) return False # Названия демонов для сервиса daemons = self.servicesDaemons[nameService] if not self.getRunDaemons(daemons, printError): flagError = True if flagError: if printError: self.printERROR(self.printNameService(nameService) + " " +\ _("service is not started")) return False return True def unicList(self, listEl): """Уникальный список с сохранением порядка""" retList = [] [not x in retList and retList.append(x) for x in listEl] return retList def setJpegPhotoUser(self, userName, photoPath, attr="uid"): """Добавляем jpeg фотографию пользователя в LDAP""" import subprocess try: FD = open(photoPath) photoData = FD.read() FD.close() except: self.printERROR(_("Not open file") + ": " + str(photoPath)) return False searchUser = self.searchLdapDN(userName, self.relUsersDN, attr) if not searchUser: self.printERROR(_("User") + " " + str(userName) + " "+\ _("not found")) return False modAttrs = [] if not self.stringIsJpeg(photoData): if self.execProg("which convert") is False: self.printERROR(_("Can not found package imagemagick")) return False flagError = False pipe = subprocess.Popen("convert '%s' jpg:-" %photoPath, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, shell=True) fOut, fIn, fErr = (pipe.stdout, pipe.stdin, pipe.stderr) fIn.close() # Код возврата retcode = pipe.wait() if retcode != 0: self.printERROR(_("Can not convert file '%s' in jpeg format")\ %photoPath) flagError = True fErr.close() if not flagError: photoData = fOut.read() if not self.stringIsJpeg(photoData): self.printERROR(\ _("Can not convert file '%s' in jpeg format") %photoPath) flagError = True fOut.close() if flagError: return False if searchUser[0][0][1].has_key('jpegPhoto'): modAttrs.append((ldap.MOD_REPLACE, 'jpegPhoto', photoData)) else: modAttrs.append((ldap.MOD_ADD, 'jpegPhoto', photoData)) userDN = self.addDN("%s=%s"%(attr,userName),self.relUsersDN) if not self.modAttrsDN(userDN, modAttrs): return False return True def removeDir(self, rmDir): """Рекурсивное удаление директории""" if not os.path.exists(rmDir): self.printERROR(_("Not found remove dir %s") %rmDir) return False fileObj = cl_profile._file() # Сканируем директорию scanObjs = fileObj.scanDirs([rmDir]) for fileRm in scanObjs[0].files: # Удаляем файлы os.remove(fileRm) for socketRm in scanObjs[0].sockets: # Удаляем сокеты os.remove(socketRm) for fifoRm in scanObjs[0].fifo: # Удаляем fifo os.remove(fifoRm) for linkRm in scanObjs[0].links: # Удаляем ссылки os.unlink(linkRm[1]) scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x))) for dirRm in scanObjs[0].dirs: # Удаляем директории os.rmdir(dirRm) os.rmdir(rmDir) return True def removeEmptyDir(self, rmDir): """Удаление пустых директорий""" if not os.path.exists(rmDir): self.printERROR(_("Not found remove dir %s") %rmDir) return False rDir = rmDir while os.listdir(rDir) == []: os.rmdir(rDir) rDir = os.path.split(rDir)[0] if rDir == "/": break return True def createUserDir(self, uid, gid, userDir, mode=0700): """Создание пользовательской директории""" if not os.path.exists(userDir): os.makedirs(userDir) if mode: os.chmod(userDir,mode) os.chown(userDir,uid,gid) return True else: self.printERROR(_("Path %s exists") %userDir) return False def createUserFile(self, fileName, fileTxt, uid, gid, mode=0644): """Создает пользовательский файл с содержимым Если директория файла не существует то ошибка """ userDir = os.path.split(fileName)[0] if not os.path.exists(userDir): self.printERROR(_("Path %s not exists") %userDir) return False fd = os.open(fileName, os.O_CREAT) os.close(fd) os.chmod(fileName, mode) os.chown(fileName,uid,gid) if fileTxt: FD = open(fileName, "r+") FD.write(fileTxt) FD.close() return True def getMailHistoryData(self,options): """Get mail history params from env and cmdline""" if not "history" in options and ("history-path" in options or "history-domains" in options): if "history-path" in options: param = "history-path" else: param = "history-domains" self.printERROR(_("Command line incorrect, " "'%s' is not using without 'history'")%param) return False if "history-domains" in options: history_domain = options["history-domains"].strip() self.clVars.Set("sr_mail_history_domain", history_domain) else: history_domain = self.clVars.Get("sr_mail_history_domain") if "history" in options: history = options["history"].strip() if history in ("on", "off"): self.clVars.Set("sr_mail_history", history) else : self.printERROR(\ _("Command line incorrect, \ 'history=%s' - error, to use 'history on' or 'history off'")\ %str(history)) return False else: history = self.clVars.Get("sr_mail_history") if history == "on" and not history_domain: self.clVars.Set("sr_mail_history_domain", self.clVars.Get("sr_mail_host")) if "history-path" in options: history_path = options["history-path"].strip() self.clVars.Set("sr_mail_history_path", history_path) else: history_path = self.clVars.Get("sr_mail_history_path") return history,history_domain,history_path def saveVarsClient(self, listVarName): """Записывает переменные для клиента calcualte-client""" #считаем переменные для клиента dictVar = {} flagError = False for varName in listVarName: value = self.clVars.Get(varName) if not value and value != "": self.printERROR(_("Variables %s are empty")%varName) flagError = True break dictVar[varName] = value if flagError: return False #Запишем переменные в клиентскую секцию for name,value in dictVar.items(): value = str(value) if not value.strip(): self.clVars.Delete(name) if not self.clVars.Write(name,value,True,"remote","client"): self.printERROR(_("Error writing variable %s")%name) flagError = True break if flagError: return False return True def isServiceSetup(self, service, printError=True): """Проверяет установлен ли сервис""" if not self.clVars: # Cоздаем объект переменные self.createClVars() if self.clVars.Get("sr_%s_set"%service) == "on": return True if printError: self.printERROR(_("Service %s is not installed")%service) return False def raw_input(self, promptText="", inputText=""): """Создает поле ввода promptText - текст перед полем ввода inputText - текст в поле ввода """ if inputText: # Записываем текст для последующего вывода в строке ввода readline.set_pre_input_hook(lambda:\ readline.insert_text(inputText) or\ readline.redisplay()) strInput = "" if promptText: # Получаем текст введенный пользователем strInput = raw_input(promptText) else: strInput = raw_input() if inputText: # Сбрасываем строку ввода readline.set_pre_input_hook(None) return strInput def isCorrectStringNet(self, strNetworks, checkNet=True): """Проверяет на корректность строку доверительных сетей Выводит cписок сетей """ splNet = strNetworks.replace(","," ").split(" ") if checkNet: checkIP = False res=re.compile("^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?\/\d\d?$") else: checkIP = True res=re.compile("^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?$") flagError = False networks = [] for i in splNet: r = i.strip() if not r: continue find =res.search(r) if not find: flagError = True break else: splIP = map(lambda x: 255>=int(x.split("/")[0]) and\ x.split("/")[0], find.group().split(".")) if not splIP[0] or splIP[0] and int(splIP[0]) == 0: flagError = True break if not splIP[3] or splIP[3] and int(splIP[3]) == 255: flagError = True break if checkNet: netList = r.split("/") if len(netList)==2: try: netMaskInt = int(netList[1]) except: flagError = True break if netMaskInt>31 or netMaskInt<4: flagError = True break else: flagError = True break if checkIP and splIP[3] and int(splIP[3]) == 0: flagError = True break for t in splIP: if t == False: flagError = True break if flagError: break networks.append(r) if flagError: return False else: return list(set(networks)) def getUserAllowNetwork(self, strPrompt, strNetAllow): """Получаем от пользователя доверительные сети вывод - список доверительных сетей """ def printW(): print _("Incorrect string allow networks") print _("Example - allow networks: 10.0.0.0/24 10.0.10.0/24") print _("Try again\n") strNet = self.raw_input(strPrompt, strNetAllow) i = 0 while i<3 and not self.isCorrectStringNet(strNet): printW() strNet = self.raw_input(strPrompt, strNet) i +=1 if i == 3 and not self.isCorrectStringNet(strNet): printW() self.printERROR(_("You used four attempts, \ if you want to continue to run the program again")) return False return self.isCorrectStringNet(strNet) def copyDir(self, destDir, srcDir): """Копируем директорию в другое место При копировании сохраняются владелец, группа, права """ if os.path.exists(destDir) and not os.listdir(destDir): os.rmdir(destDir) if not os.path.exists(destDir): # Создаем директорию os.makedirs(destDir) # Файловый объект fileObj = cl_profile._file() # Сканируем директорию scanObjs = fileObj.scanDirs([srcDir]) if not scanObjs: return True for dirSrc in scanObjs[0].dirs: #создаем в домашней директории директории из srcDir dirName = destDir + dirSrc.split(srcDir)[1] os.mkdir(dirName) mode,uid,gid = fileObj.getModeFile(dirSrc) os.chown(dirName, uid,gid) os.chmod(destDir, mode) for fileCopy in scanObjs[0].files: oldFile = destDir + fileCopy.split(srcDir)[1] #копируем файлы fileObj.openFiles(fileCopy, oldFile) fileObj.saveOldFile() fileObj.oldProfile = False fileObj.closeFiles() os.chown(oldFile, fileObj._uid, fileObj._gid) os.chmod(oldFile, fileObj._mode) for linkCreate in scanObjs[0].links: #копируем ссылки dst = destDir + linkCreate[1].split(srcDir)[1] srcDestList = linkCreate[0].split(srcDir) if len(srcDestList)>1: src = destDir + srcDestList[1] else: src = linkCreate[0] os.symlink(src,dst) if os.path.exists(dst): mode,uid,gid = fileObj.getModeFile(dst) #Изменение прав на ссылки os.lchown(dst, uid, gid) # Удаляем сокеты for rmSocket in scanObjs[0].sockets: os.remove(rmSocket) # Удаляем fifo for rmFifo in scanObjs[0].fifo: os.remove(rmFifo) mode,uid,gid = fileObj.getModeFile(srcDir) os.chmod(destDir, mode) os.chown(destDir, uid,gid) return True @adminConnectLdap def addEntry(self, DN, entry, errorMessage): """Добавление узла в LDAP""" try: self.conLdap.add_s(DN, entry) except ldap.LDAPError, e: self.printERROR(_("LDAP Error") + ": " + e[0]['desc'].strip()) self.printERROR(errorMessage) return False return True def addDN(self, *arg): """Складывает текстовые элементы DN""" DNs = [] for dn in arg: if dn: DNs.append(dn) return ','.join(DNs) @adminConnectLdap def initialChecks(self, service, printError=True): """Начальная проверка перед запуском методов сервиса""" if self.clVars.Get("sr_mail_relay_set") == "on": if printError: self.printERROR(_("This server is a mail relay. \ This command is not allowed.")) return False if not self.isServiceSetup(service, printError): return False return True def initialChecksSetup(self): # Создаем объект переменных self.createClVars() """Начальная проверка перед запуском метода setup""" if self.clVars.Get("sr_mail_relay_set") == "on": self.printERROR(_("This server is a mail relay. \ This command is not allowed.")) return False return True def chownR(self, directory, uid, gid): """изменяет владельца и группу для всех файлов и директорий внутри directory """ fileObj = cl_profile._file() scanObjs = fileObj.scanDirs([directory]) # меняем владельца домашней директории os.chown(directory, uid,gid) # Меняем владельца директорий for dirCh in scanObjs[0].dirs: os.chown(dirCh, uid,gid) # Меняем владельца файлов for fileCh in scanObjs[0].files: os.chown(fileCh, uid,gid) # Меняем владельца ссылок for linkCh in scanObjs[0].links: os.lchown(linkCh[1], uid, gid) return True @adminConnectLdap def modAttrsDN(self, relDN, modAttrs): """Модифицирует аттрибуты DN""" DN = self.addDN(relDN,self.baseDN) if modAttrs: try: self.conLdap.modify_s(DN, modAttrs) except ldap.LDAPError, e: self.printERROR(e[0]['desc']) return False return True @adminConnectLdap def modifyElemDN(self, relDN, newFirstDn): """Изменяет основной элемент DN (uid, cn и др.)""" DN = self.addDN(relDN,self.baseDN) try: self.conLdap.modrdn_s(DN, newFirstDn) except ldap.LDAPError, e: self.printERROR(e[0]['desc']) return False return True @adminConnectLdap def delDN(self, relDN): """Удаляет одиночный DN""" DN = self.addDN(relDN,self.baseDN) try: self.conLdap.delete_s(DN) except ldap.LDAPError, e: self.printERROR(e[0]['desc']) return False return True def getMaxAttrDN(self, relDN, name, attr, numMin, numMax, attrSearch): """Находит максимальный добавленный аттрибут в LDAP DN""" resSearch = self.searchLdapDN(name, relDN, attr, [attrSearch]) lst = [] lst.append(0) if resSearch: for scope in resSearch: if scope[0][1].has_key(attrSearch): uid = int(scope[0][1][attrSearch][0]) if uid<=numMax and uid>=numMin: lst.append(uid) return max(lst) return False @adminConnectLdap def fullElementDNtoText(self, relDN="", ldapFilter='(objectclass=*)'): """Выводит все внутренние элементы DN виде текста""" DN = self.addDN(relDN, self.baseDN) listDN=[] try: dnList = self.conLdap.search_s(DN, ldap.SCOPE_SUBTREE, ldapFilter,None) except ldap.LDAPError, e: self.printERROR("fullElementDN: "+e[0]['desc']) return False FDOUT = StringIO.StringIO("") writer = LDIFWriter(FDOUT) for dn, f in dnList: writer.unparse(dn, f) FDOUT.seek(0) return FDOUT.read() @adminConnectLdap def fullElementSambaDNtoText(self, relDN=""): """Выводит все внутренние элементы ветки Samba в виде текста""" return self.fullElementDNtoText(relDN,'(|(|(|(|(ou:dn:=Samba)\ (ou:dn:=Unix))(ou:dn:=LDAP))(!(ou:dn:=Services)))(ou=Services))') @adminConnectLdap def fullElementUnixDNtoText(self, relDN=""): """Выводит все внутренние элементы ветки Unix в виде текста""" return self.fullElementDNtoText(relDN,'(|(|(|(ou:dn:=Unix)\ (ou:dn:=LDAP))(!(ou:dn:=Services)))(ou=Services))') @adminConnectLdap def fullElementMailDNtoText(self, relDN=""): """Выводит все внутренние элементы ветки Mail в виде текста""" baseDN = self.clVars.Get("ld_base_dn") baseDNName, baseLogin = baseDN.split(",")[0].split("=") proxyDN = self.clVars.Get("ld_bind_dn") proxyDNName, proxyLogin = proxyDN.split(",")[0].split("=") #return self.fullElementDNtoText(relDN,'(&(|(|(&(ou:dn:=Replication)\ #(ou:dn:=Mail))(!(ou:dn:=Services)))(ou=Services))(!(&(%s:dn:=%s)\ #(%s:dn:=%s))))'%(proxyDNName, proxyLogin, baseDNName, baseLogin)) return self.fullElementDNtoText(relDN,'(&(&(|(|(|(ou:dn:=LDAP)\ (ou=Mail))(!(ou:dn:=Services)))(ou=Services))(!(&(%s:dn:=%s)(%s:dn:=%s))))\ (!(ou:dn:=Worked)))'%(proxyDNName, proxyLogin, baseDNName, baseLogin)) @adminConnectLdap def fullElementMailSambaDNtoText(self, relDN=""): """Выводит все внутренние элементы ветки Samba и Mail в виде текста""" return self.fullElementDNtoText(relDN,'(&(|(|(|(|(|(ou:dn:=Samba)\ (ou:dn:=Unix))(ou:dn:=LDAP))(ou:dn:=Mail))(!(ou:dn:=Services)))(ou=Services))\ (!(|(&(&(ou:dn:=Users)(ou:dn:=Mail))(uid=*))(&(&(ou:dn:=Groups)(ou:dn:=Mail))\ (cn=*)))))') @adminConnectLdap def fullElementMailUnixDNtoText(self, relDN=""): """Выводит все внутренние элементы ветки Unix и Mail в виде текста""" return self.fullElementDNtoText(relDN,'(&(|(|(|(|(ou:dn:=Unix)\ (ou:dn:=LDAP))(ou:dn:=Mail))(!(ou:dn:=Services)))(ou=Services))\ (!(|(&(&(ou:dn:=Users)(ou:dn:=Mail))(uid=*))(&(&(ou:dn:=Groups)(ou:dn:=Mail))\ (cn=*)))))') def deleteServiceVarsInFile(self, service): """Удаляет переменные сервиса из ini файлов После запуска этого метода объект self.clVars должен быть пересоздан """ importVarsDict = self.createClVars(False,True) serviceNameVars = "_%s_" %service for location in importVarsDict.keys(): for nameVar in importVarsDict[location]: # Если имя сервиса присутствует в переменной - # Удаляем переменную if serviceNameVars in nameVar: if not self.clVars.Delete(nameVar, location, "server"): return False self.clVars = False return True @adminConnectLdap def deleteDN(self, relDelDN): """Удаляет DN и все внутренние элементы""" delDN = self.addDN(relDelDN, self.baseDN) delListDN=[] try: dnList = self.conLdap.search_s(delDN, ldap.SCOPE_SUBTREE, '(objectclass=*)', ['']) except ldap.LDAPError, e: self.printERROR("deleteDN: "+e[0]['desc']) return False for dn, f in dnList: delListDN.append(dn) delListDN.sort(lambda x, y: cmp(len(y), len(x))) for dn in delListDN: try: self.conLdap.delete_s(dn) except ldap.LDAPError, e: self.printERROR("deleteDN: "+e[0]['desc']) return False return True def execProg(self, cmdStrProg, inStr=False, retFull=True, envProg={}): """Выполняет внешнюю программу Параметры: cmdStrProg внешняя программа inStr данные передаваемые программе на страндартный вход. Возвращаемые параметры: строка которую выведет внешняя программа или False в случае ошибки """ env_path = {"PATH":cl_utils.getpathenv()} env = {} env.update(os.environ.items() + env_path.items() + envProg.items()) retCode,programOut = cl_utils.runOsCommand(cmdStrProg,inStr,retFull,env) if not retCode: return programOut return False def createLdif(self, ldifFile): """Cоздает ldif из ldif - профиля""" if not os.access(ldifFile, os.F_OK): self.setError(_("File not found") + ":\n " + ldifFile) return False FD = open (ldifFile) ldifProfile = FD.read() FD.close() clProf = cl_profile.profile(self.clVars) # Применяем условия к профилю ldifProfile = clProf.applyTermsProfile(ldifProfile,ldifFile) # Заменяем переменные ldifProfile = clProf.applyVarsProfile(ldifProfile,ldifFile) return ldifProfile def searchLineInFile(self, name, fileName, numEl=0): """Ищет строку в которой есть название разделенное ':' в файле похожем на /etc/passwd""" if os.path.exists(fileName): FD = open(fileName) lines = FD.readlines() FD.close() lineFound = "" for line in lines: if name == line.split(":")[numEl]: lineFound = line break if lineFound: return lineFound else: return False def getMaxInFile(self, fileName, numMin, numMax, numEl=2): """Получаем максимальный номер из файла похожего на /etc/group""" lst = [] lst.append(0) if os.path.exists(fileName): FD = open(fileName) lines = FD.readlines() FD.close() for line in lines: if not ':' in line: continue num = int(line.split(":")[numEl]) if num<=numMax and num>=numMin: lst.append(num) return max(lst) return False def getLdapObjInFile(self, part="admin"): """Получаем объект ldapFunction из ini файла В выходном объекте есть соединение с LDAP сервером: self.conLdap """ # Если раннее была ошибка то выходим if self.getError(): self.printERROR (_("ERROR") + ": " +\ self.getError().strip()) return False ldapParser = iniLdapParser() adminDn = ldapParser.getVar(part,"DN") adminPw = ldapParser.getVar(part,"PASS") if not (adminDn or adminPw): if part == "admin": service = "LDAP" else: service = part self.printERROR(\ _("Admin password for the service %s could not be found")%service) return False ldapObj = ldapFunction(adminDn, adminPw) # Генератор задержек wait = self.genSleep() while ldapObj.getError(): try: # Задержка wait.next() except StopIteration: break # Очистка ошибки cl_profile._error.error = [] ldapObj = ldapFunction(adminDn, adminPw) if ldapObj.getError(): # Удаляем одинаковые ошибки listError = [] for e in ldapObj.error: if not e in listError: listError.append(e) cl_profile._error.error = listError self.printERROR (_("LDAP connect error") + ": " +\ ldapObj.getError().strip()) return False # Устанавливаем у объекта соединение и объект LDAP функций self.ldapObj = ldapObj self.conLdap = ldapObj.conLdap return True def dialogYn(self, message): def getChar(): fd = sys.stdin.fileno() oldSet = termios.tcgetattr(fd) tty.setraw(fd) char = sys.stdin.read(1) termios.tcsetattr(fd, termios.TCSADRAIN, oldSet) return char def term(char): if ord(char) == 3: return None if char == "Y": return True elif char == "n": return False else: char = getChar() return term(char) sys.stdout.write(message + ":") char = getChar() res = term(char) sys.stdout.write("\n") return res def dialogYesNo(self, message): sys.stdout.write(message + ": ") strIn=sys.stdin.readline().lower().strip() sys.stdout.write("\n") if "yes" == strIn: return True elif "no" == strIn: return False else: return self.dialogYesNo(message) def createJabberCertificate(self): # создаем сертификат если есть используем прежний if not os.path.exists("/etc/jabber/ssl.pem"): if os.path.exists("/etc/jabber/self-cert.sh"): self.execProg("/bin/bash /etc/jabber/self-cert.sh") else: # Создаем сертификат для Ejabberd if not self.createCertificate(sslOrganization=\ "Automatically-generated ejabberd SSL key", userName="jabber", groupName="jabber", certFile="/etc/jabber/ssl.pem", genDH=True): return False return True def createMailCertificate(self): if not self.createCertificate(sslOrganization="Dovecot IMAP Server", userName="dovecot", groupName="mail", certFile="/etc/ssl/dovecot/server.pem", dhFile="/etc/ssl/dovecot/dh.pem", genDH=True, keyFile="/etc/ssl/dovecot/server.key"): return False # Создаем сертификат для Postfix if not self.createCertificate(sslOrganization="Postfix IMAP Server", userName="postfix", groupName="postfix", certFile="/etc/ssl/postfix/server.crt", keyFile="/etc/ssl/postfix/server.key"): return False return True def createCertificate(self, sslCountry="US", sslState="California", sslLocality="Santa Barbara", sslOrganization="SSL Server", sslUnit="For Testing Purposes Only", sslCommonName="localhost", sslEmail="root@localhost", nsCertType="server", sslDays=730, sslBits=1024, userName="root",groupName="root", certFile="/tmp/server.pem", certFileMode=0400, keyFile="/tmp/server.key", keyFileMode=0400, dhFile=None, dhFileMode=0400, genDH=False): """Создает сертификат""" sslFile = "/usr/bin/openssl" strData = time.strftime("%Y%m%d%H%M%S",time.localtime(time.time())) if not os.path.exists(sslFile): self.printERROR(_("Can not found %s")%sslFile) return False if genDH and dhFile: certAndKeyFiles = [dhFile, certFile, keyFile] foundCertFiles = filter(lambda x: os.path.exists(x), certAndKeyFiles) if not os.path.exists(dhFile): rndFile = "/tmp/%s.rnd" %strData self.execProg("dd if=/dev/urandom of=%s count=1"%rndFile) if not os.path.exists(rndFile): self.printERROR(_("Can not create %s")%rndFile) return False self.printOK( _("Generating DH. This is going to take a long time") + " ...", printBR=False) textLine = self.execProg("%s dhparam -dsaparam -rand %s 4096 >> %s"\ %(sslFile, rndFile, dhFile)) if textLine == False: self.printERROR(_("Can not create DH certificate %s")%certFile) return False if os.path.exists(rndFile): os.remove(rndFile) foundCertFiles = filter(lambda x: os.path.exists(x), certAndKeyFiles) if len(foundCertFiles)==3: return True else: if genDH: keyFile = certFile certAndKeyFiles = [certFile] foundCertFiles = filter(lambda x: os.path.exists(x),certAndKeyFiles) if len(foundCertFiles)==1: return True else: certAndKeyFiles = [certFile, keyFile] foundCertFiles = filter(lambda x: os.path.exists(x), certAndKeyFiles) if len(foundCertFiles)==2: return True # Удаляем файл сертификата map(lambda x: os.remove(x), foundCertFiles) uidAndGid = self.getUserUidAndGid(userName, groupName) if not uidAndGid: return False uid, gid = uidAndGid textCnf="""[ req ] prompt = no default_bits = %s distinguished_name = req_dn [ req_dn ] C = %s ST = %s L = %s O = %s OU = %s CN = %s emailAddress = %s [ cert_type ] nsCertType = %s """%(sslBits, sslCountry, sslState, sslLocality, sslOrganization, sslUnit, sslCommonName, sslEmail, nsCertType) # генерируем название файла конфигурации cnfFile = "/tmp/%s.cnf" %strData if genDH: rndFile = "/tmp/%s.rnd" %strData self.execProg("dd if=/dev/urandom of=%s count=1"%rndFile) if not os.path.exists(rndFile): self.printERROR(_("Can not create %s")%rndFile) return False # Cоздание директорий for fileName in certAndKeyFiles: dirName = os.path.split(fileName)[0] if not os.path.exists(dirName): self.createUserDir(0, 0, dirName, 0755) # Создание конфигурационного файла self.createUserFile(cnfFile, textCnf, 0, 0, 0600) # Создание сертификата textLine = self.execProg(\ "%s req -new -x509 -nodes -config %s -days %s -out %s -keyout %s"\ %(sslFile, cnfFile, sslDays, certFile, keyFile)) if textLine == False: self.printERROR(_("Can not create certificate %s")%certFile) return False # Создание DH if genDH: self.printOK( _("Generating DH. This is going to take a long time") + " ...", printBR=False) textLine = self.execProg("%s dhparam -dsaparam -rand %s 4096 >> %s"\ %(sslFile, rndFile, certFile)) if textLine == False: self.printERROR(_("Can not create DH certificate %s")%certFile) return False if os.path.exists(rndFile): os.remove(rndFile) # Удаление конфигурационного файла if os.path.exists(cnfFile): os.remove(cnfFile) # Меняем права if os.path.exists(certFile): os.chown(certFile, uid,gid) os.chmod(certFile, certFileMode) if os.path.exists(keyFile): os.chown(keyFile, uid,gid) os.chmod(keyFile, keyFileMode) if textLine == False: self.printERROR(_("Can not create certificate %s")%certFile) return False # Проверка сертификата textLine = self.execProg("%s x509 -subject -fingerprint -noout -in %s"\ %(sslFile, certFile)) if textLine == False: self.printERROR(_("Can not create certificate %s")%certFile) return False return True def createClVars(self, clVars=False, returnImportVar=False): """Создает объект Vars""" # Словарь импортируемых переменных из ini Файлов dictImportVars = {} if not clVars: clVars = cl_base.DataVars() clVars.flServer() dictImportVars = clVars.flIniFile() # Устанавливаем у объекта объект Vars self.clVars = clVars if returnImportVar: return dictImportVars return True @adminConnectLdap def searchLdapDN(self, name, relDN, attr, retAttr=None): """Находит DN в LDAP""" DN = self.addDN(relDN,self.baseDN) #searchScope = ldap.SCOPE_SUBTREE searchScope = ldap.SCOPE_ONELEVEL searchFilter = "%s=%s" %(attr,name) retrieveAttributes = retAttr resSearch = self.ldapObj.ldapSearch(DN, searchScope, searchFilter, retrieveAttributes) return resSearch class servUnix(shareLdap): """Методы севисa Unix""" # минимальное и максимальное значение gid-ов системных групп #(Computers, и.т. д) maxSysGid = 999 minSysGid = 900 relGrDN = 'ou=Groups' relUsDN = 'ou=Users' relServDN = 'ou=Unix' # Коментарий к группе по умолчанию groupGecos = "Calculate group" # Базовая директория пользователей baseDir = "/home" # Название пользователя по умолчанию fullNameUser = "Calculate user" # Оболочка пользователя по умолчанию userShell = "/bin/bash" # Скелетная директория для создания пользователя skelDir = "/etc/skel" # Алгоритм шифрования пароля для LDAP пользователя userCrypt = "ssha" # Используемые ldif файлы ldifFileMachine =\ "/usr/lib/calculate/calculate-server/ldif/samba_machine.ldif" ldifFileUser = "/usr/lib/calculate/calculate-server/ldif/unix_user.ldif" ldifFileGroup = "/usr/lib/calculate/calculate-server/ldif/unix_group.ldif" ldifFileBase = "/usr/lib/calculate/calculate-server/ldif/unix_base.ldif" def __init__(self, smbObj=False): shareLdap.__init__(self) # максимальный и минимальный uid self.maxUid = self.getUidMax() self.minUid = self.getUidMin() # максимальный и минимальный gid self.maxGid = self.maxUid self.minGid = self.minUid self.relDN = self.addDN(self.relServDN,self.ServicesDN) # DN пользователей, относительно базового DN self.relUsersDN = self.addDN(self.relUsDN, self.relDN) # DN групп пользователей, относительно базового DN self.relGroupsDN = self.addDN(self.relGrDN, self.relDN) if smbObj: # получаем объект сервиса Samba self.servSambaObj = smbObj else: # создаем объект сервиса Samba self.servSambaObj = servSamba(self) # создаем объект сервиса Mail self.servMailObj = servMail(self) # DN, компьютеров относительно базового DN self.relComputersDN = self.servSambaObj.relComputersDN def getLdapObjInFile(self): """Cоединение с LDAP администратором Unix сервиса""" return shareLdap.getLdapObjInFile(self, "unix") def createHomeDir(self, userName, homeDir, skelDir): """Создаем домашнюю директорию пользователя создание происходит после создания пользователя """ resLdap = self.searchUnixUser(userName) if resLdap: uid = int(resLdap[0][0][1]['uidNumber'][0]) gid = int(resLdap[0][0][1]['gidNumber'][0]) else: return False if not os.path.exists(homeDir): # Создаем домашнюю директорию os.makedirs(homeDir) # Файловый объект fileObj = cl_profile._file() # Сканируем скелетную директорию scanObjs = fileObj.scanDirs([skelDir]) if not scanObjs: return True for dirCreate in scanObjs[0].dirs: #создаем в домашней директории директории из /etc/skel dirName = homeDir + dirCreate.split(skelDir)[1] mode,tmpUid,tmpGid = fileObj.getModeFile(dirCreate) os.mkdir(dirName,mode) os.chown(dirName, uid,gid) for fileCopy in scanObjs[0].files: oldFile = homeDir + fileCopy.split(skelDir)[1] #копируем файлы fileObj.openFiles(fileCopy, oldFile) fileObj.saveOldFile() fileObj.oldProfile = False fileObj.closeFiles() os.chown(oldFile, uid,gid) for linkCreate in scanObjs[0].links: #копируем ссылки dst = homeDir + linkCreate[1].split(skelDir)[1] srcHomeList = linkCreate[0].split(skelDir) if len(srcHomeList)>1: src = homeDir + srcHomeList[1] else: src = linkCreate[0] os.symlink(src,dst) #Изменение прав на ссылки os.lchown(dst, uid, gid) os.chmod(homeDir, 0700) os.chown(homeDir, uid,gid) return True def searchPasswdUser(self, userName): """Ищет пользователей в /etc/passwd""" filePasswd = "/etc/passwd" return self.searchLineInFile(userName, filePasswd) def searchGroupGid(self, groupId): """Ищет gid в /etc/group""" gid = str(groupId) fileGroup = "/etc/group" return self.searchLineInFile(gid, fileGroup, 2) def searchGroupGroupName(self, groupName): """Ищет имя группы в /etc/group""" fileGroup = "/etc/group" return self.searchLineInFile(groupName, fileGroup) def searchUnixGroupName(self, groupName): """Находит группу сервиса Unix по её имени""" resSearch = self.searchLdapDN(groupName, self.relGroupsDN, "cn") return resSearch def searchUnixUser(self, userName): """Находит пользователя сервиса Unix""" resSearch = self.searchLdapDN(userName, self.relUsersDN, "uid") return resSearch def searchUnixUserPrimGroup(self, groupId): """Находит пользователей с первичной группой groupId""" resSearch = self.searchLdapDN(str(groupId), self.relUsersDN, "gidNumber") return resSearch def searchUnixGid(self, groupId): """Находит группу сервиса Unix по ёе id""" resSearch = self.searchLdapDN(str(groupId), self.relGroupsDN, "gidNumber") return resSearch def searchUnixMemberGid(self, userName): """Ищет группы сервиса Unix в котрых есть данный пользователь""" resSearch = self.searchLdapDN(userName, self.relGroupsDN, "memberUid") return resSearch def searchUidPasswd(self, userId): """Находит пользователя по его идентефикатору из /etc/passwd""" filePasswd = "/etc/passwd" return self.searchLineInFile(str(userId), filePasswd, 2) def searchUidUnix(self, userId): """Находит пользователя по его идентефикатору из LDAP""" resSearch = self.searchLdapDN(str(userId), self.relUsersDN, "uidNumber") return resSearch def searchGroupsUnix(self, userGroups, printError=True): """Ищет список групп из списка userGroups в LDAP Список групп может состоять из чисел или названий групп Возвращает (результат выполнения,словарь имен групп,сообщение о ошибке) """ userGroupNames = {} flagError = False gidErrors = [] groupErrors = [] for gid in userGroups: try: int(gid) except: groupName = gid res = self.searchUnixGroupName(groupName) if not res: groupErrors.append(groupName) flagError = True continue userGroupNames[res[0][0][1]['cn'][0]]=\ res[0][0][1]['gidNumber'][0] continue gidNumber = gid res = self.searchUnixGid(gidNumber) if not res: gidErrors.append(gidNumber) flagError = True continue userGroupNames[res[0][0][1]['cn'][0]] = res[0][0][1]['gidNumber'][0] if flagError: errorMessage = "" if groupErrors: errorGroup=_("Group names (%s) is not found in Unix service")\ %", ".join(groupErrors) errorMessage = errorGroup if printError: self.printERROR(errorGroup) if gidErrors: errorGid=_("Group numbers (%s) is not found in Unix service")\ %", ".join(gidErrors) errorMessage += errorGid if printError: self.printERROR(errorGid) return (False, userGroupNames, errorMessage) return (True, userGroupNames, "") def searchGroupsGroups(self, userGroups, printError=True): """Ищет список групп из списка userGroups в /etc/group Список групп может состоять из чисел или названий групп Возвращает список имен групп """ userGroupNames = [] flagInt = True for gid in userGroups: try: int(gid) except: flagInt = False break flagError = False if flagInt: for gidNumber in userGroups: res = self.searchGroupGid(gidNumber) if not res: flagError = True break userGroupNames.append(res.split(':')[0]) if flagError: if printError: self.printERROR( _("Group number %s is not found in") %\ str(gidNumber) + " /etc/group") return False else: for groupName in userGroups: res = self.searchGroupGroupName(groupName) if not res: flagError = True break if flagError: if printError: self.printERROR( _("Group name %s is not found in") %\ str(groupName) + " /etc/group") return False userGroupNames = userGroups return userGroupNames def searchUsersInGroupUnix(self, usersNames, groupName): """Ищет спиcок пользователей в группе, ищет в Unix В случае успеха выводит список найденных пользователей если нет группы False если ничего не найдено пустой список """ res = self.searchUnixGroupName(groupName) if not res: return False else: findUsers = [] if res[0][0][1].has_key('memberUid'): usersInGroup = res[0][0][1]['memberUid'] for userName in usersNames: if userName in usersInGroup: findUsers.append(userName) return findUsers def searchUsersInGroupGroup(self, usersNames, groupName): """Ищет спиcок пользователей в группе, ищет в /etc/groups В случае успеха выводит список найденных пользователей если нет группы False если ничего не найдено пустой список """ res = self.searchGroupGroupName(groupName) if not res: return False else: findUsers = [] res = res.rstrip() usersInGroup = res.split(':')[3] if not usersInGroup: return findUsers usersInGroup = usersInGroup.split(',') for userName in usersNames: if userName in usersInGroup: findUsers.append(userName) return findUsers @adminConnectLdap def addGroupUnixServer(self, groupName, options, printSuccess=True): """Добавляет группу пользователей Unix""" # Проверим установлен ли сервис unix if not self.initialChecks("unix"): return False # Если группа существует выходим без ошибки flagSearchGroups = True if options.has_key('f'): flagSearchGroups = False if flagSearchGroups and self.searchGroupGroupName(groupName): self.printERROR(\ _("group name %s is found in") % str(groupName) +\ " /etc/group") return False if self.searchUnixGroupName(groupName): self.printERROR(\ _("group name %s is found in Unix service") %\ str(groupName)) return False # Ищем название группы в Samba сервисе if self.isServiceSetup("samba", False) and\ self.servSambaObj.searchSambaGroupName(groupName): self.printERROR(_("group name %s is found in Samba service") %\ str(groupName)) return False self.clVars.Set("ur_group",groupName) # номер группы gid = str(self.getMaxGid()) if options.has_key('g'): gid = options['g'] try: int(gid) except: self.printERROR(_("GID must be is number")) return False if flagSearchGroups and self.searchGroupGid(gid): self.printERROR(_("GID is found in") + " /etc/group") return False if self.searchUnixGid(gid): self.printERROR(_("GID is found in Unix service")) return False # Ищем gid в Samba сервисе if self.isServiceSetup("samba", False) and\ self.servSambaObj.searchSambaGid(gid): self.printERROR(_("GID is found in Samba service")) return False self.clVars.Set("ur_group_id", gid) # Коментарий к группе gecos = self.groupGecos if options.has_key('c'): gecos = options['c'] self.clVars.Set("ur_group_comment",gecos) ldifFile = self.ldifFileGroup groupLdif = self.createLdif(ldifFile) if not groupLdif: print self.getError() return False if not self.ldapObj.getError(): self.ldapObj.ldapAdd(groupLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False if options.has_key('p'): sys.stdout.write(gid) else: if printSuccess: self.printSUCCESS(_("Added group '%s' in Unix service")\ %groupName) return True @adminConnectLdap def addMachineLdapServer(self, machineName, options): """Добавляет Unix машину в LDAP-сервер""" # Проверим установлен ли сервис unix if not self.initialChecks("unix"): return False machineLogin = machineName.replace('$','') + "$" groupName = self.clVars.Get('sr_samba_machine_group') # Проверяем установлен ли сервис Samba if not self.isServiceSetup("samba"): return False resSearch = self.servSambaObj.searchSambaGroupName(groupName) if resSearch: groupId = resSearch[0][0][1]['gidNumber'][0] else: gr = self.staticGroups["Domain Computers"] groupId = gr.gid opt = {} opt['c'] = gr.comment opt['t'] = gr.type if gr.sid: opt['s'] = gr.sid else: opt['r'] = gr.rid opt['g'] = gr.gid groupName = gr.name if not self.servSambaObj.addGroupSambaServer(groupName, opt): return False self.clVars.Set('sr_samba_machine_login', machineLogin) # Находим последний добавленный id userIdNumber = str(self.getMaxUid()) self.clVars.Set('sr_samba_machine_id',userIdNumber) self.clVars.Set('sr_samba_machine_gid',groupId) ldifFile = self.ldifFileMachine userLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): #Добавляем пользователя в LDAP self.ldapObj.ldapAdd(userLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False self.printSUCCESS(_("Added machine")) return True @adminConnectLdap def addUserUnixServer(self,userName,options,printSuccess=True,pwd=False, callSamba=False): """Добавляет Unix пользователя в LDAP-сервер""" # Проверим установлен ли сервис unix if not self.initialChecks("unix"): return False if self.searchUnixUser(userName): self.printERROR(_("User exists in Unix service")) return False elif self.searchPasswdUser(userName): self.printERROR(_("User exists in") + " /etc/passwd") return False # id нового пользователя userId = str(self.getMaxUid()) self.clVars.Set("ur_name", userName) baseDir = self.baseDir # Базовая домашняя директория if options.has_key('b'): baseDir = options['b'] # Устанавливаем скелетную директорию if options.has_key('k'): skelDir = options['k'] else: skelDir = self.skelDir # Устанавливаем домашнюю директорию if options.has_key('d'): homeDir = options['d'] else: homeDir = os.path.join(baseDir, userName) self.clVars.Set("ur_home_path",homeDir) fullNameUser = self.fullNameUser # Полное имя пользователя if options.has_key('c'): fullNameUser = options['c'] self.clVars.Set("ur_fio",fullNameUser) # По умолчанию пользователя не видно visible = '0' if options.has_key('v'): visible = '1' self.clVars.Set("ur_visible",visible) # Оболочка пользователя userShell = self.userShell if options.has_key('s'): userShell = options['s'] self.clVars.Set("ur_shell", userShell) # id пользователя if options.has_key('u'): userId = options['u'] try: int(userId) except: self.printERROR(_("UID is not number")) return False if self.searchUidUnix(userId): self.printERROR("UID %s "%userId + \ _("exists in Unix service")) return False if self.searchUidPasswd(userId): self.printERROR("UID %s "%userId+_("exists in") + \ " /etc/passwd") return False self.clVars.Set("ur_id",userId) # Добавляем пользователя в группы (находим имена групп) if options.has_key('G'): userGroups = options['G'].split(',') data = self.servSambaObj.searchUnixAndSambaGroups(userGroups, callSamba) if data and type(data) == types.TupleType: userGroupNamesUnix, userGroupNamesSamba = data else: return False userGid = str(self.getMaxGid()) # Группа пользователя if options.has_key('g'): userGid = options['g'] retCondUnix, userGidNamesUnix, errMessUnix =\ self.searchGroupsUnix([userGid], False) userGidNamesUnix = userGidNamesUnix.keys() userGidNamesSamba = False # В случае вызова из Samba объекта if callSamba: retCondSamba, userGidNamesSamba, errMessSamba =\ self.servSambaObj.searchGroupsSamba([userGid], False) userGidNamesSamba = userGidNamesSamba.keys() userGidNamesPasswd = self.searchGroupsGroups([userGid], False) if userGidNamesUnix: #Имя группы пользователя groupName = userGidNamesUnix[0] elif userGidNamesSamba: #Имя группы пользователя groupName = userGidNamesSamba[0] elif userGidNamesPasswd: #Имя группы пользователя groupName = userGidNamesPasswd[0] resGroup = self.searchGroupGroupName(groupName) groupGid = "" if resGroup: groupGid = resGroup.split(":")[2] self.printERROR( _("Group name %s is found in")%str(groupName) +\ " /etc/group") if groupGid: self.printWARNING(_("Create a group in LDAP")) self.printWARNING(" cl-groupadd -f -g %s %s unix"\ %(groupGid,str(groupName))) return False else: self.printERROR( _("Group %s is not found") % str(userGid)) return False else: if self.searchGroupGroupName(userName): self.printERROR( _("Group name %s is found in")%str(userName) +\ " /etc/group") return False if self.searchUnixGroupName(userName): self.printERROR( _("Group name %s is found in Unix serivce")%str(userName)) return False if self.isServiceSetup("samba", False) and\ self.servSambaObj.searchSambaGroupName(userName): self.printERROR( _("Group name %s is found in Samba serivce")%str(userName)) return False if pwd: userPwd = pwd else: userPwd = self.getUserPassword(options, "p", "P") if userPwd == False: return False if not userPwd: userPwdHash = "crypt{xxx}" else: userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) if not userPwdHash: return False self.clVars.Set("ur_hash",userPwdHash) # флаги добавления flagAdd = {} # Добавление основной группы пользователя if options.has_key('g'): resLdap = self.searchUnixGroupName(groupName) if not resLdap and callSamba: resLdap = self.servSambaObj.searchSambaGroupName(groupName) resGroup = self.searchGroupGroupName(groupName) if not (resLdap or resGroup): self.printERROR (_("ERROR") + ": " +\ _("group") + " " + userGid + " " + _("is not found")) return False if resGroup: userGid = resGroup.split(":")[2] if resLdap: userGid = resLdap[0][0][1]['gidNumber'][0] else: flagAddGroup = self.addGroupUnixServer(userName,{},False) flagAdd['group'] = flagAddGroup if not flagAddGroup: return False self.clVars.Set("ur_gid", userGid) ldifFile = self.ldifFileUser userLdif = self.createLdif(ldifFile) flagError = False if not self.ldapObj.getError(): #Добавляем пользователя в LDAP self.ldapObj.ldapAdd(userLdif) #Добавляем пользователя в дополнительные группы (опция G) if options.has_key('G') and userGroupNamesUnix: for group in userGroupNamesUnix: if not self.addUsersGroupUnix([userName], group): flagError = True break # не переделывать на else if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() flagError = True removeHomeBack = False if not flagError: # Востановим (home на сервере) удаленного пользователя message = _("Do you want to restore deleted user %s data?")\ %userName + "\n" + "'yes', 'no'" resHomeDir = self.restorePathDelUser(userName, homeDir, "unix/home", message, self) if not resHomeDir: flagError = True createDirHome = False else: term, createDirHome, removeHomeBack = resHomeDir # Удаляем бекап домашней директории на сервере (удаленного польз..) if not flagError and removeHomeBack and\ os.path.exists(removeHomeBack): self.removeDir(removeHomeBack) self.removeEmptyDir(os.path.split(removeHomeBack)[0]) # Изменим время последнего измения пароля пользователя if not flagError and not self.setShadowLastChange(userName): flagError = True # Добавим домашнюю директорию if not flagError and createDirHome and options.has_key('m'): if not os.path.exists(homeDir): if not self.createHomeDir(userName, homeDir, skelDir): self.printERROR (_("ERROR") + ": " +\ _("cannot create HOME dir")) flagError = True #загружаем картинку if not flagError and options.has_key('i'): photoFile = options['i'] if not self.setJpegPhotoUser(userName, photoFile): self.printERROR(_("Can not add jpeg photo for user") + " " +\ str(userName)) flagError = True if flagError: self.delUserUnixServer(userName, {}, False, False) self.printERROR (_("Can not add user")+ " " + str(userName)) return False if printSuccess: if flagAdd.has_key('group'): self.printSUCCESS(_("Added group in Unix service")) if createDirHome and options.has_key('m'): self.printSUCCESS(_("Created home dir %s")%homeDir) if options.has_key('i'): self.printSUCCESS(_("Added jpeg photo %s")% photoFile) self.printSUCCESS(_("Added user in Unix service")) return True def setUserJabberID(self, userName, jabberID): """Устанавливает для пользователя jabberID""" searchUser = self.searchUnixUser(userName) if not searchUser: return True modAttrs = [] if searchUser[0][0][1].has_key('registeredAddress'): modAttrs.append((ldap.MOD_REPLACE, 'registeredAddress', jabberID)) else: modAttrs.append((ldap.MOD_ADD, 'registeredAddress', jabberID)) userDN = self.addDN('uid='+userName,self.relUsersDN) if not self.modAttrsDN(userDN, modAttrs): self.printERROR(_("Can not modify registeredAddress attribute in \ Unix service")) return False return True def getUserJabberID(self, userName): """Выдаем jabberID""" searchUser = self.searchUnixUser(userName) if not searchUser: self.printERROR(_("User %s not found in Unix service")\ %str(userName)) return False if searchUser[0][0][1].has_key('registeredAddress'): return searchUser[0][0][1]['registeredAddress'][0] else: return "" def deleteUserJabberID(self, userName): """Удаляет jabberID пользователя""" if self.getUserJabberID(userName): modAttrs =[(ldap.MOD_DELETE, 'registeredAddress', None)] userDN = self.addDN('uid='+userName,self.relUsersDN) if not self.modAttrsDN(userDN, modAttrs): self.printERROR(_("Can not delete registeredAddress attribute \ in Unix service")) return False return True def setUserMail(self, userName, mail): """Устанавливает для пользователя основной почтовый адрес""" searchUser = self.searchUnixUser(userName) if not searchUser: self.printERROR(_("User %s not found in Unix service")\ %str(userName)) return False modAttrs = [] if searchUser[0][0][1].has_key('mail'): modAttrs.append((ldap.MOD_REPLACE, 'mail', mail)) else: modAttrs.append((ldap.MOD_ADD, 'mail', mail)) userDN = self.addDN('uid='+userName,self.relUsersDN) if not self.modAttrsDN(userDN, modAttrs): self.printERROR(_("Can not modify mail attribute in Unix service")) return False return True def getUserMail(self, userName): """Выдаем основной почтовый адрес""" searchUser = self.searchUnixUser(userName) if not searchUser: self.printERROR(_("User %s not found in Unix service")\ %str(userName)) return False if searchUser[0][0][1].has_key('mail'): return searchUser[0][0][1]['mail'][0] else: return "" def deleteUserMail(self, userName): """Удаляет почтовый адрес пользователя""" if self.getUserMail(userName): modAttrs =[(ldap.MOD_DELETE, 'mail', None)] userDN = self.addDN('uid='+userName,self.relUsersDN) if not self.modAttrsDN(userDN, modAttrs): self.printERROR(_("Can not delete mail attribute in Unix \ service")) return False return True def addUsersGroupUnix(self, users, groupName): """Добавляет пользователей из списка в Unix группу""" if not self.searchUnixGroupName(groupName): self.printERROR(_("group name is not found in Unix service")) return False flagFalse = False for userName in users: if not (self.searchUnixUser(userName) or\ self.searchPasswdUser(userName)): self.printERROR(\ _("User %s is not found")%str(userName)) flagFalse = True break if flagFalse: return False foundUsersLdap = self.searchUsersInGroupUnix(users, groupName) foundUsersGroup = self.searchUsersInGroupGroup(users, groupName) foundUsers = [] if foundUsersLdap and foundUsersGroup: foundUsers = self.unicList(foundUsersLdap + foundUsersGroup) elif foundUsersLdap: foundUsers = foundUsersLdap elif foundUsersGroup: foundUsers = foundUsersGroup addUsers = [] for user in users: if not(user in foundUsers): addUsers.append(user) modAttrs = [] for userName in addUsers: modAttrs.append((ldap.MOD_ADD, 'memberUid', userName)) if modAttrs: groupDN = self.addDN("cn="+groupName, self.relGroupsDN) return self.modAttrsDN(groupDN, modAttrs) return True def getMaxGidUnix(self): """Находит максимальный добавленный gid в Unix""" return self.getMaxAttrDN(self.relGroupsDN, "*", "cn", self.minGid, self.maxGid, "gidNumber") def getMaxGidUnixSystem(self): """Находит максимальный добавленный gid в LDAP системной группы""" return self.getMaxAttrDN(self.relGroupsDN, "*", "cn", self.minSysGid, self.maxSysGid, "gidNumber") def getMaxGid(self): """Находит максимальный gid +1""" maxGidLdap = self.getMaxGidUnix() maxGidGroup = self.getMaxGidGroup() maxGids = [maxGidGroup, maxGidLdap] if self.isServiceSetup("samba", False): maxGidSamba = self.servSambaObj.getMaxGidSamba() maxGids.append(maxGidSamba) maxGid = max(map(lambda x: int(x), maxGids)) if maxGid == 0: return self.minGid else: return maxGid+1 def getMaxGidGroupSystem(self): """Получаем максимальный добавленный gid из /etc/group системной группы """ fileGroup = "/etc/group" return self.getMaxInFile(fileGroup, self.minSysGid, self.maxSysGid) def getMaxGidGroup(self): """Получаем максимальный добавленный gid из /etc/group""" fileGroup = "/etc/group" return self.getMaxInFile(fileGroup, self.minGid, self.maxGid) def getMaxGidSystem(self): """Находит максимальный gid +1 системной группы""" maxGidLdap = self.getMaxGidUnixSystem() maxGidGroup = self.getMaxGidGroupSystem() if maxGidLdap > maxGidGroup: maxGid = maxGidLdap else: maxGid = maxGidGroup if maxGid == 0: return self.minSysGid else: return maxGid+1 def getUidMin(self): """Получаем начальный UID пользователя""" fileLogin = "/etc/login.defs" fileAdduser = "/etc/adduser.conf" minUid = 1000 if os.path.exists(fileLogin): FD = open(fileLogin) lines = FD.readlines() FD.close() for line in lines: if "UID_MIN" in line and not "#" in line: s = re.compile("\s+") minUid = int(s.split(line)[1]) break elif os.path.exists(fileAdduser): FD = open(fileLogin) lines = FD.readlines() FD.close() for line in lines: if "FIRST_UID" in line and not "#" in line: minUid = int(line.split('=')[1]) break return minUid def getUidMax(self): """Получаем конечный UID пользователя""" fileLogin = "/etc/login.defs" fileAdduser = "/etc/adduser.conf" maxUid = 29999 if os.path.exists(fileLogin): FD = open(fileLogin) lines = FD.readlines() FD.close() for line in lines: if "UID_MAX" in line and not "#" in line: s = re.compile("\s+") maxUid = int(s.split(line)[1]) break elif os.path.exists(fileAdduser): FD = open(fileLogin) lines = FD.readlines() FD.close() for line in lines: if "LAST_UID" in line and not "#" in line: maxUid = int(line.split('=')[1]) break return maxUid def getMaxUidPasswd(self): """Получаем максимальный добавленный id из /etc/passwd""" filePasswd = "/etc/passwd" return self.getMaxInFile(filePasswd, self.minUid, self.maxUid) def getMaxUidUnix(self, relDn=False): """Находит максимальный добавленный id в сервисе Unix""" if relDn: return self.getMaxAttrDN(relDn, "*", "uid", self.minUid, self.maxUid, "uidNumber") else: return self.getMaxAttrDN(self.relUsersDN, "*", "uid", self.minUid, self.maxUid, "uidNumber") def getMaxUid(self): """Находит максимальный id +1""" # Ветка компьютеры maxUidLdapComp = self.getMaxUidUnix(self.relComputersDN) maxUidLdap = self.getMaxUidUnix() maxUidPasswd = self.getMaxUidPasswd() listUid = [maxUidLdapComp, maxUidLdap, maxUidPasswd] maxUid = max(listUid) if maxUid == 0: return self.minUid else: return maxUid+1 def delUserUnixServer(self, userName, options, printSuccess=True, backup=True): """Удаляем Unix пользователя""" # Проверим установлен ли сервис unix if not self.initialChecks("unix"): return False # Ищем пользователя в Samba if self.isServiceSetup("samba", False) and\ self.servSambaObj.searchSambaUser(userName): self.printERROR (_("ERROR") + ": " +\ _("User %s is found in Samba service") %\ str(userName)) self.printWARNING(\ _("At first, need remove user from Samba service")) return False # Ищем пользователя в Mail if self.isServiceSetup("mail", False) and\ self.servMailObj.searchMailUserToName(userName): self.printERROR (_("ERROR") + ": " +\ _("User %s is found in Mail service")%str(userName)) self.printWARNING(_("At first, need remove user from Mail service")) return False # Ищем пользователя в Unix resLdap = self.searchUnixUser(userName) if not resLdap: self.printERROR (_("ERROR") + ": " +\ _("User %s is not found in Unix service") % str(userName)) return False if options.has_key('r'): backup = False homeDir = False if resLdap[0][0][1].has_key('homeDirectory'): #Домашняя директория пользователя homeDir = resLdap[0][0][1]['homeDirectory'][0] if backup and os.path.exists(homeDir) and\ os.path.isdir(homeDir) and os.listdir(homeDir): # Делаем сохранение домашней директории if not self.backupDelUser(userName, 'unix/home', homeDir, self): return False # Удаляем пользователя delDN = self.addDN("uid=" + userName, self.relUsersDN) if not self.delDN(delDN): return False # Удаляем пользователя из групп if not self.delUserInGroup(userName): return False if resLdap[0][0][1].has_key('gidNumber'): gid = resLdap[0][0][1]['gidNumber'][0] else: resPasswd = self.searchPasswdUser(userName) if resPasswd: gid = resPasswd.split(":")[3] #Находим основную группу пользователя resGroup = False if gid: resGroup = self.searchUnixGid(gid) # Если установлен Samba сервис и группа не найдена в Unix сервисе if not resGroup and self.isServiceSetup("samba", False): resGroupSamba = self.servSambaObj.searchSambaGid(gid) if resGroupSamba: # В случае отсутствия других пользователей удаляем # основную группу в Samba сервисе if not resGroupSamba[0][0][1].has_key('memberUid'): groupName = resGroupSamba[0][0][1]['cn'][0] # Находим группы у которых есть аттрибут type groupsSambaList = filter(\ lambda x: x[1].type, self.staticGroups.items()) groupsSamba = {} groupsSamba.update(groupsSambaList) # Группы которые нельзя удалять # при удалении пользователя notDeletedGroups = groupsSamba.keys() if not groupName in notDeletedGroups: if not self.servSambaObj.delGroupSambaServer(\ groupName, {}, False): return False if resGroup: # В случае отсутствия других пользователей # удаляем основную группу в Unix сервисе if not resGroup[0][0][1].has_key('memberUid'): groupName = resGroup[0][0][1]['cn'][0] if not self.delGroupUnixServer(groupName, {}, False): return False # Удаляем пользователя из ветки Worked в случае репликации objRepl = servRepl() if not objRepl.delReplWorkedUser(userName): self.printERROR (_("ERROR") + ": " +\ _("Can not remove user %s in the LDAP branch 'Worked'")\ % str(userName)) return False # Удаляем домашнюю директорию if homeDir and os.path.exists(homeDir) and os.path.isdir(homeDir)\ and self.removeDir(homeDir): if printSuccess: self.printSUCCESS( _("Home directory %s is removed")% str(homeDir)) if printSuccess: self.printSUCCESS(_("User %s is deleted")%userName) return True def delGroupUnixServer(self, groupName, options, printSuccess=True, checkPrimaryGroup=True): """Удаляет группу пользователей Unix""" # Проверим установлен ли сервис unix if not self.initialChecks("unix"): return False res = self.searchUnixGroupName(groupName) if not res: self.printERROR(\ _("Group %s is not found in Unix service")%groupName) return False if checkPrimaryGroup: groupId = res[0][0][1]['gidNumber'][0] if self.searchUnixUserPrimGroup(groupId): self.printWARNING(_("cannot remove user's primary group") + ".") return True delDN = self.addDN("cn="+groupName, self.relGroupsDN) res = self.delDN(delDN) if res: if printSuccess: self.printSUCCESS( _("Group %s is deleted")%groupName) return True else: self.printERROR(_("Can not delete group") + " " + groupName) return False def modUserUnixServer(self, userName, options, printSuccess=True, callSamba=False): """Модифицирует настройки пользователя Unix в LDAP""" # Проверим установлен ли сервис unix if not self.initialChecks("unix"): return False res = self.searchUnixUser(userName) if not res: self.printERROR( _("User %s is not found in Unix service")%str(userName)) return False # Новые группы в которые входит пользователь if options.has_key('G'): userGroups = options['G'].split(',') data = self.servSambaObj.searchUnixAndSambaGroups(userGroups, callSamba) if data and type(data) == types.TupleType: userGroupNamesUnix, userGroupNamesSamba = data else: return False # Удаляем Unix пользователя из групп в которые он входит if not self.delUserInGroup(userName): return False flagError = False for group in userGroupNamesUnix: if not self.addUsersGroupUnix([userName], group): flagError = True break if flagError: return False if printSuccess: self.printSUCCESS(_("Replaced list of supplementary group")) # Добавляем группы в которые входит пользователь elif options.has_key('a'): userGroups = options['a'].split(',') data = self.servSambaObj.searchUnixAndSambaGroups(userGroups, callSamba) if data and type(data) == types.TupleType: userGroupNamesUnix, userGroupNamesSamba = data else: return False flagError = False for group in userGroupNamesUnix: if not self.addUsersGroupUnix([userName], group): flagError = True break if flagError: return False if printSuccess: self.printSUCCESS(\ _("Appended the user to the supplemental groups")) # Изменяемые аттрибуты пользователя modAttrs = [] # Изменяем первичную группу пользователя if options.has_key('g'): newFirstGroup = options['g'] # В случае вызова из Samba объекта ищем gid в Unix и Samba if callSamba: retCondUnix, userGroupNames, errMessUnix =\ self.searchGroupsUnix([newFirstGroup],False) userGroupNames = userGroupNames.keys() if not userGroupNames: retCondSamba ,userGroupNames, errMessSamba =\ self.servSambaObj.searchGroupsSamba([newFirstGroup], False) userGroupNames = userGroupNames.keys() if not userGroupNames: self.printERROR(\ _("Group %s is not found in Unix and Samba services")%\ str(newFirstGroup)) return False else: retCondUnix, userGroupNames, errMessUnix =\ self.searchGroupsUnix([newFirstGroup]) userGroupNames = userGroupNames.keys() if not retCondUnix: return False groupName = userGroupNames[0] resLdap = self.searchUnixGroupName(groupName) if callSamba and not resLdap: resLdap = self.servSambaObj.searchSambaGroupName(groupName) resGroup = self.searchGroupGroupName(groupName) if not (resLdap or resGroup): self.printERROR (_("ERROR") + ": " +\ _("not found group ") + groupName) return False if resGroup: userGid = resGroup.split(":")[2] if resLdap: userGid = resLdap[0][0][1]['gidNumber'][0] modAttrs += [(ldap.MOD_REPLACE, 'gidNumber', userGid)] visible = False # пользователя видно if options.has_key('V'): visible = '1' # пользователя не видно if options.has_key('I'): visible = '0' if visible: modAttrs += [(ldap.MOD_REPLACE, 'shadowFlag', visible)] # Изменяем домашнюю директорию if options.has_key('d'): homeDir = options['d'] modAttrs += [(ldap.MOD_REPLACE, 'homeDirectory', homeDir)] # Включаем пользователя if options.has_key('U'): modAttrs += [(ldap.MOD_REPLACE, 'shadowExpire', "-1")] # Выключаем пользователя if options.has_key('L'): modAttrs += [(ldap.MOD_REPLACE, 'shadowExpire', "1")] # Изменяем комментарий к пользователю if options.has_key('c'): comment = options['c'] if res[0][0][1].has_key('displayName'): modAttrs += [(ldap.MOD_REPLACE, 'displayName', comment), (ldap.MOD_REPLACE, 'cn', comment)] else: modAttrs += [(ldap.MOD_REPLACE, 'cn', comment)] # Изменяем оболочку пользователя if options.has_key('s'): shell = options['s'] modAttrs.append((ldap.MOD_REPLACE, 'loginShell', shell)) # Изменяем пароль пользователя userPwd = self.getUserPassword(options, "p", "P") if userPwd == False: return False if userPwd: userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) if not userPwdHash: return False if res[0][0][1].has_key('userPassword'): modAttrs.append((ldap.MOD_REPLACE, 'userPassword', userPwdHash)) else: modAttrs.append((ldap.MOD_ADD, 'userPassword', userPwdHash)) if modAttrs: DN = self.addDN("uid="+userName, self.relUsersDN) if not self.modAttrsDN(DN, modAttrs): return False # Переносим домашнюю директорию пользователя if options.has_key('d') and options.has_key('m'): homeDirOld = res[0][0][1]['homeDirectory'][0] homeDirNew = homeDir textLine = self.execProg("mv %s %s" %(homeDirOld, homeDirNew)) if textLine == False: self.printERROR(_("Can not move home directory")) modAttrs = [(ldap.MOD_REPLACE, 'homeDirectory', homeDirOld)] self.modAttrsDN(DN, modAttrs) return False else: if printSuccess: self.printSUCCESS(_("Moved home directory")) if options.has_key('P') or options.has_key('p'): # Изменим время последнего измения пароля пользователя if not self.setShadowLastChange(userName): return False if printSuccess: self.printSUCCESS(\ _("Modified user password of Unix service")) if printSuccess: if options.has_key('g'): flagInt = False try: int(newFirstGroup) flagInt = True except: self.printSUCCESS(_("Modified primary group to %s")\ %newFirstGroup) if flagInt: self.printSUCCESS(_("Modified GID primary group to %s")\ %newFirstGroup) if options.has_key('c'): self.printSUCCESS(_("Modified comment")) if options.has_key('s'): self.printSUCCESS(_("Modified shell")) if options.has_key('d'): self.printSUCCESS(_("Modified home directory")) if options.has_key('U'): self.printSUCCESS(_("Unlocked user %s")% str(userName)) if options.has_key('I'): self.printSUCCESS(\ _("User %s is invisible")% str(userName)) if options.has_key('V'): self.printSUCCESS(_("User %s is visible")% str(userName)) if options.has_key('L'): self.printSUCCESS(_("Locked user %s")% str(userName)) return True def modUserUnixPasswd(self, userName, options, pwd=False): """Устанавливает пароль LDAP пользователя и меняет его опции""" # Проверим установлен ли сервис unix if not self.initialChecks("unix"): return False res = self.searchUnixUser(userName) if not res: self.printERROR( _("User %s is not found in Unix service")%str(userName)) return False # Изменяемые аттрибуты пользователя modAttrs = [] # Удаляем пароль пользователя if options.has_key('d'): if res[0][0][1].has_key('userPassword'): modAttrs += [(ldap.MOD_DELETE, 'userPassword', None)] else: self.printERROR(\ _("User %s has not password for Unix service")%\ str(userName)) # Включаем пользователя if options.has_key('u'): modAttrs += [(ldap.MOD_REPLACE, 'shadowExpire', "-1")] # Выключаем пользователя elif options.has_key('l'): modAttrs += [(ldap.MOD_REPLACE, 'shadowExpire', "1")] if not options: optPasswd = {"p":""} if pwd: userPwd = pwd else: userPwd = self.getUserPassword(optPasswd, "p", False) if userPwd == False: return False userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) if not userPwdHash: return False if res[0][0][1].has_key('userPassword'): modAttrs.append((ldap.MOD_REPLACE, 'userPassword', userPwdHash)) else: modAttrs.append((ldap.MOD_ADD, 'userPassword', userPwdHash)) if modAttrs: DN = self.addDN("uid="+userName, self.relUsersDN) if not self.modAttrsDN(DN, modAttrs): return False if options.has_key('d'): self.printSUCCESS( _("Deleted password of Unix service for user")+ " " +\ str(userName)) if options.has_key('l'): self.printSUCCESS(_("Locked user") + " " + str(userName) +\ " " +_("of Unix service")) if options.has_key('u'): self.printSUCCESS(_("Unlocked user") + " " + str(userName) +\ " " +_("of Unix service")) if not options: self.printSUCCESS(_("User password of Unix service changed")) # Изменим время последнего измения пароля пользователя if not self.setShadowLastChange(userName): return False return True return False def modGroupUnixServer(self, groupName, options, printSuccess=True): """Модифицирует настройки группы пользователей LDAP""" # Проверим установлен ли сервис unix if not self.initialChecks("unix"): return False if not self.searchUnixGroupName(groupName): self.printERROR(_("group name not found in Unix service")) return False # Добавляем список пользователей в группу if options.has_key('a'): # добавляемые пользователи в группу users = options['a'].split(',') res = self.addUsersGroupUnix(users, groupName) if res: if printSuccess: self.printSUCCESS(_("Appended list of users to group") +\ " " + str(groupName)) else: self.printERROR(_("Can not append list of users to group") +\ " " + str(groupName)) return False # Удаляем список пользователей из группы if options.has_key('d'): # удаляемые пользователи из группы users = options['d'].split(',') res = self.delUsersGroupUnix(users, groupName) if res: if printSuccess: self.printSUCCESS(_("Deleted list users from group")+" "+\ str(groupName)) else: self.printERROR(_("Can not delete list users from group") +\ " " + str(groupName)) return False modGroupName = groupName # Изменяем имя группы if options.has_key('n'): newGroupName = options['n'] if self.searchUnixGroupName(newGroupName): self.printERROR( _("group name %s is found in Unix service")%\ str(newGroupName)) return False # Ищем название группы в Samba сервисе if self.isServiceSetup("samba", False) and\ self.servSambaObj.searchSambaGroupName(newGroupName): self.printERROR( _("group name %s is found in Samba service")%\ str(newGroupName)) return False newFirstDn = "cn=" + newGroupName oldDN = self.addDN("cn=" + groupName, self.relGroupsDN) res = self.modifyElemDN(oldDN, newFirstDn) if res: modGroupName = newGroupName if printSuccess: self.printSUCCESS(_("Group renamed to %s")\ %newGroupName) else: self.printERROR(_("Can not rename group")) return False modAttrs = [] # Изменяем комментарий к группе if options.has_key('c'): gecos = options['c'] modAttrs.append((ldap.MOD_REPLACE, 'description', gecos)) if modAttrs: groupDN = self.addDN("cn=" + modGroupName, self.relGroupsDN) res = self.modAttrsDN(groupDN, modAttrs) if res: if options.has_key('c'): if printSuccess: self.printSUCCESS(_("Modified group comment")) return True else: if options.has_key('c'): self.printSUCCESS(_("Can not modify group comment")) return False return True def delUserInGroup(self, userName): """Удаление из групп в которые входит пользователь""" userInGroups = self.searchUnixMemberGid(userName) modAttrs = [(ldap.MOD_DELETE, 'memberUid', userName)] flagError = False for group in userInGroups: groupName = group[0][1]['cn'][0] groupDN = self.addDN("cn=" + groupName, self.relGroupsDN) if not self.modAttrsDN(groupDN, modAttrs): flagError = True break if flagError: return False else: return True def delUsersGroupUnix(self, users, groupName): """Удаление пользователей из списка из группы Unix""" def getPrimaryUsers(): gidNumber = res[0][0][1]["gidNumber"][0] searchUsers = self.searchUnixUserPrimGroup(gidNumber) foundUserNames = [] if searchUsers: for data in searchUsers: foundUserNames.append(data[0][1]["uid"][0]) if foundUserNames: primaryUsers = list(set(foundUserNames)&set(users)) if primaryUsers: self.printERROR(_("%s is primary group")% groupName + " " +\ _("for users (%s)")%", ".join(primaryUsers)) return False return True res = self.searchUnixGroupName(groupName) if not res : self.printERROR(_("group name is not found in Unix service")) return False if not res[0][0][1].has_key("memberUid"): if not getPrimaryUsers(): return False self.printERROR( _("Member list of group %s is empty")%str(groupName)) return False memberUsers = res[0][0][1]["memberUid"] flagError =False for user in users: if not user in memberUsers: flagError = True break if flagError: if not getPrimaryUsers(): return False self.printERROR( _("User %s is not found in group")%str(user)+" "+\ str(groupName)) return False modAttrs = [] for userName in users: modAttrs.append((ldap.MOD_DELETE, 'memberUid', userName)) groupDN = self.addDN("cn="+groupName, self.relGroupsDN) return self.modAttrsDN(groupDN, modAttrs) def setupUnixServer(self, options): """Начальная настройка Unix сервиса""" # Принудительная установка forceOptions = False # Создаем объект переменных и начальная проверка if not self.initialChecksSetup(): return False if options.has_key("f"): forceOptions = True # В случае если сервер установлен if self.clVars.Get("sr_unix_set") == "on" and\ not forceOptions: self.printWARNING (_("WARNING") + ": " +\ _("Unix service already configured")+ ".") return True if not self.clVars.Get("sr_ldap_set") == "on": self.printERROR(_("LDAP service not setuped")) self.printWARNING(_("Setup LDAP service")) self.printWARNING(" cl-setup ldap") return False if not forceOptions: # предупреждение при выполнении этой программы будут изменены # конфигурационные файлы и база данных сервиса 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 self.dialogYesNo(messDialog): return True else: # делаем backup # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False bakupObj = servLdap() if not bakupObj.backupServer(): return False # Удаляем переменные сервиса в ini файлах self.deleteServiceVarsInFile("unix") # Cоздаем объект переменные self.createClVars() # Объект сервис репликации servReplObj = servRepl() foundReplication = False # проверяем на присутствие серверов репликации for replServ in servReplObj.replServices: if self.clVars.Get("ld_repl_%s_servers"%replServ): foundReplication = True break if not foundReplication: # Если серверов репликации нет # удаляем переменные репликации servReplObj.clVars = self.clVars servReplObj.deleteVars() # Cоздаем объект переменные self.createClVars() # Имя устанавливаемого сервиса self.clVars.Set("cl_pass_service","unix") self.clVars.Write("sr_unix_set","off") # Cоздаем объект профиль устанавливая директорию ldap для # файлов профилей if not self.applyProfilesFromService('unix'): return False # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False else: if not self.restartLdapServer(): return False #Cоединение с Ldap (администратор) if not shareLdap.getLdapObjInFile(self): return False # Удаляем предыдущую ветку сервиса Unix servicesDN = self.relDN resSearch = self.searchService() if resSearch: delDN = self.relDN if self.deleteDN(delDN): self.printOK(_("Removed Unix DN from LDAP database") + " ...") else: self.printERROR(\ _("Can not remove Unix DN from LDAP database")) return False # в случае отключения репликации if self.clVars.Get("ld_repl_set") != "on": # Объект сервис репликации servReplObj = servRepl() # Удаляем служебную ветку ldap if not servReplObj.delSysDN(): return False ldifFile = self.ldifFileBase baseLdif = self.createLdif(ldifFile) 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") + " ...") # Записываем данные администратора сервиса Unix ldapParser = iniLdapParser() ldapParser.setVar("unix", {"DN":self.clVars.Get("ld_unix_dn"), "PASS":self.clVars.Get("ld_unix_pw")}) self.printOK(_("Unix service configured") + " ...") self.clVars.Write("sr_unix_set","on") return True def setShadowLastChange(self, userName): """Изменим последнюю дату измениня пароля на текущую""" # число дней от 1970 года date = int(time.time()/86400) modAttrs = [(ldap.MOD_REPLACE, 'shadowLastChange', str(date))] userDN = self.addDN('uid='+userName,self.relUsersDN) if not self.modAttrsDN(userDN, modAttrs): self.printERROR(_("Can not modify shadowLastChange attribute")) return False return True class servMail(shareLdap): """Методы сервиса Mail""" relGrDN = 'ou=Groups' relUsDN = 'ou=Users' relServDN = 'ou=Mail' ldifFileBase = "/usr/lib/calculate/calculate-server/ldif/mail_base.ldif" ldifFileUser = "/usr/lib/calculate/calculate-server/ldif/mail_user.ldif" ldifFileGroup = "/usr/lib/calculate/calculate-server/ldif/mail_group.ldif" # Алгоритм шифрования пароля для Mail пользователя userCrypt = "ssha" # Динамическая группа Unix для добавления пользователя defaultUnixGroup = {"name":"maildomain", "comment":"Default Mail Users"} def __init__(self, unixObj=False): shareLdap.__init__(self) # DN сервиса self.relDN = self.addDN(self.relServDN,self.ServicesDN) # DN пользователей, относительно базового DN self.relUsersDN = self.addDN(self.relUsDN, self.relDN) # DN групп пользователей, относительно базового DN self.relGroupsDN = self.addDN(self.relGrDN, self.relDN) # Директория хранения писем if unixObj: # получаем объект сервиса Unix self.servUnixObj = unixObj else: # создаем объект сервиса Unix self.servUnixObj = servUnix() def searchGroupsMail(self, userGroups, printError=True): """Ищет список групп из списка userGroups в Mail сервисе Список групп может состоять из названий групп или их почтовых адресов Возвращает список названий групп """ userGroupNames = [] flagError = False searchEmailGroup = True searchNameGroup = True for userGroup in userGroups: if "@" in userGroup: searchEmailGroup = self.searchGroupToMail(userGroup) if not searchEmailGroup: flagError = True break userGroupNames.append(searchEmailGroup[0][0][1]['cn'][0]) else: searchNameGroup = self.searchMailGroupToName(userGroup) if not searchNameGroup: flagError = True break userGroupNames.append(userGroup) if flagError: if printError: if not searchEmailGroup: self.printERROR( _("Email address %s is not found in Mail service")%\ str(userGroup)) elif not searchNameGroup: self.printERROR( _("Group name %s is not found in Mail service")%\ str(userGroup)) return False return userGroupNames def delUserMailServer(self,userName,options,printSuccess=True,backup=True): """Удаляем Mail пользователя""" # Проверим установлен ли сервис Mail if not self.initialChecks("mail"): return False # Ищем Mail пользователя resSearch = self.searchMailUserToName(userName) if not resSearch: self.printERROR (_("ERROR") + ": " +\ _("User %s is not found in Mail service") % str(userName)) return False #почтовая директория пользователя mailDir = os.path.join(self.clVars.Get("sr_mail_path"), userName) if options.has_key('r'): backup = False # Делаем сохранение данных удаляемого пользователя if backup and os.path.exists(mailDir) and os.listdir(mailDir): if not self.backupDelUser(userName, 'mail', mailDir): return False # Удаляем почту из Unix сервиса if self.servUnixObj.searchUnixUser(userName): if not self.servUnixObj.deleteUserMail(userName): return False # Удаляем реплицируемый алиас для этого пользователя if self.clVars.Get("ld_repl_mail_set") == "on": # Объект сервис репликации servReplObj = servRepl() if not servReplObj.delReplMailAlias(userName): self.printERROR (_("ERROR") + ": " +\ _("Cannot delete email alias \ for user %s in 'Replication/Mail' branch") %str(userName)) return False # Удаляем пользователя из групп if not self.delUserInGroup(userName): return False # Удаляем пользователя delDN = self.addDN("uid=" + userName, self.relUsersDN) if not self.delDN(delDN): return False # Удаляем почтовую папку if os.path.exists(mailDir) and self.removeDir(mailDir): if printSuccess: self.printSUCCESS(\ _("Mail user directory %s is removed")% str(mailDir)) if printSuccess: self.printSUCCESS(_("Mail user %s is deleted")%userName) return True def searchMailGroupToName(self, groupName): """Находит группу сервиса Unix по её имени""" resSearch = self.searchLdapDN(groupName, self.relGroupsDN, "cn") return resSearch def searchMailGroup(self, nameOrMali): """Находит группу сервиса Mail по имени или email""" if "@" in nameOrMali: resSearch = self.searchGroupToMail(nameOrMali) else: resSearch = self.searchMailGroupToName(nameOrMali) return resSearch def searchMailMember(self, nameOrMail, printError=True): """Ищет группы сервиса Unix в котрых есть данный пользователь Поиск происходит по email или имени пользователя """ resSearchUser = self.searchMailUser(nameOrMail) if not resSearchUser: if printError: self.printERROR(\ _("Mail user or email %s are not found in Mail service")%\ str(nameOrMail)) return False userMail = resSearchUser[0][0][1]['mail'][0] resSearchGroup = self.searchLdapDN(userMail, self.relGroupsDN, "rfc822member") return (userMail, resSearchGroup) def delUserInGroup(self, userName): """Удаление из групп в которые входит пользователь""" resSearch = self.searchMailMember(userName) if not resSearch: return False userMail = resSearch[0] userInGroups = resSearch[1] modAttrs = [(ldap.MOD_DELETE, 'rfc822member', userMail)] flagError = False for group in userInGroups: groupName = group[0][1]['cn'][0] groupDN = self.addDN("cn=" + groupName, self.relGroupsDN) if not self.modAttrsDN(groupDN, modAttrs): flagError = True break if flagError: return False else: return True def delUsersGroupMail(self, users, groupName): """Удаление пользователей из списка из группы Mail""" res = self.searchMailGroupToName(groupName) if not res : self.printERROR(_("group name is not found in Mail service")) return False if not res[0][0][1].has_key("rfc822member"): self.printERROR(\ _("Member list of group %s is empty")%str(groupName)) return False memberMailUsers = res[0][0][1]["rfc822member"] flagError = False memberUsers = {} for mailUser in memberMailUsers: userName = mailUser.split("@")[0] memberUsers[userName] = mailUser for user in users: if not user in memberUsers.keys(): flagError = True break if flagError: self.printERROR(\ _("User %s is not found in group")%str(user)+" "+\ str(groupName)) return False modAttrs = [] for user in users: mailUser = memberUsers[user] modAttrs.append((ldap.MOD_DELETE, 'rfc822member', mailUser)) groupDN = self.addDN("cn="+groupName, self.relGroupsDN) return self.modAttrsDN(groupDN, modAttrs) def delGroupMailServer(self, groupName, options): """Удаляет группу пользователей Mail""" # Проверим установлен ли сервис Mail if not self.initialChecks("mail"): return False res = self.searchMailGroupToName(groupName) if not res: self.printERROR( _("Group %s is not found in Mail service")%groupName) return False delDN = self.addDN("cn="+groupName, self.relGroupsDN) res = self.delDN(delDN) if res: # В случае почтовой репликации удаляем алиас в ветке # Replication/Mail # Проверяем на включение почтовой репликации if self.clVars.Get("ld_repl_mail_set") == "on": # Объект сервис репликации servReplObj = servRepl() if not servReplObj.delReplMailAlias(groupName): self.printERROR (_("ERROR") + ": " +\ _("Cannot delete email alias \ for group %s in 'Replication/Mail' branch") %str(userName)) return False self.printSUCCESS( _("Mail group %s is deleted")%groupName) return True else: self.printERROR(_("Can not delete Mail group") +\ " " + groupName) return False def delAlternateAddress(self, userName): """Удаление альтернативных адресов пользователя""" res = self.searchMailUserToName(userName) if not res: return False if not res[0][0][1].has_key('mailAlternateAddress'): return True modAttrs = [(ldap.MOD_DELETE, 'mailAlternateAddress', None)] userDN = self.addDN("uid=" + userName, self.relUsersDN) if not self.modAttrsDN(userDN, modAttrs): return False return True def modGroupMailServer(self, groupName, options): """Модифицирует настройки группы пользователей Mail""" # Проверим установлен ли сервис Mail if not self.initialChecks("mail"): return False searchGroup = self.searchMailGroupToName(groupName) if not searchGroup: self.printERROR(_("group name not found in Mail service")) return False if options.has_key('n') and options.has_key('e'): self.printERROR(_("Command Line Options '-n' and '-e' are \ incompatible, use one of the options")) return False if options.has_key('hide') and options.has_key('hide-off'): self.printERROR(_("Command Line Options '--hide' and '--hide-off' \ are incompatible, use one of the options")) return False attrDelete = [] attrDeleteFirst = [] attrAppend = [] altMails = [] # Объект сервис репликации servReplObj = False if self.clVars.Get("ld_repl_mail_set") == "on": # Объект сервис репликации servReplObj = servRepl() filterHosts = [] if options.has_key('hide'): filterHosts = options['hide'].split(",") if searchGroup[0][0][1].has_key('filtersender'): attrDeleteFirst.append((ldap.MOD_DELETE, 'filtersender', None)) domain = self.clVars.Get('os_net_domain') # Если необходимо добавляем домен к именам хостов fHosts = map(lambda x: (not '.' in x and x+"."+domain) or x, filterHosts) for host in fHosts: attrAppend.append((ldap.MOD_ADD, 'filtersender', host)) if options.has_key('hide-off'): if searchGroup[0][0][1].has_key('filtersender'): attrDeleteFirst.append((ldap.MOD_DELETE, 'filtersender', None)) if options.has_key('e'): altMails = options['e'].split(",") email = searchGroup[0][0][1]["mail"][0] altEmails = searchGroup[0][0][1]["mailAlternateAddress"] # Удаляем альтернативные адреса, кроме первого for altEmail in altEmails: if email != altEmail: attrDeleteFirst.append( (ldap.MOD_DELETE, 'mailAlternateAddress', altEmail)) i = 0 for altMail in altMails: if "@" in altMail: if len(altMail.split("@")) != 2: self.printERROR(_("Incorrect alternate adresses \ option '-e'")) return False mail = altMail else: mail = "%s@%s" %(altMail,self.clVars.Get("sr_mail_host")) searchGroupMail = self.searchGroupToMail(mail) if self.searchUserToMail(mail) or (searchGroupMail and\ (not (mail in altEmails) and len(searchGroupMail) == 1 or\ len(searchGroupMail) != 1)): self.printERROR( _("Alternate email address %s is found in Mail service")%\ str(mail)) return False if i == 0: attrAppend.append((ldap.MOD_REPLACE, 'mailAlternateAddress', mail)) else: attrAppend.append((ldap.MOD_ADD, 'mailAlternateAddress', mail)) i += 1 if servReplObj: if not altMails and filterHosts: altMails = searchGroup[0][0][1]["mailAlternateAddress"] if altMails: for mail in altMails: if "@" in altMail: mail = altMail else: mail = "%s@%s" %(altMail,\ self.clVars.Get("sr_mail_host")) foundReplAlias = servReplObj.searchMailAddress(mail) if foundReplAlias: flagError = False foundReplUsers = foundReplAlias[0][0][1]['cn'] for foundReplUser in foundReplUsers: if foundReplUser!=groupName: flagError = True break if flagError: self.printERROR(_("Mail address %s is found in \ 'Replication/Mail' branch")%mail) self.printERROR(_("The address belongs to \ mail user or group: %s")%foundReplUser) return False if not servReplObj.modReplMailAlias(groupName, altMails, filterHosts): errorMsg = _("Can not set replication mail alias,") +\ " " + _("for name %s")%groupName + " " +\ "(%s)"%", ".join(altMails) self.printERROR(errorMsg) return False if options.has_key('hide-off'): if not servReplObj.deleteHideHosts(groupName): errorMsg = _("Can not delete hide host in mail alias,") +\ " " + _("for name %s")%groupName self.printERROR(errorMsg) return False # Добавляем список пользователей в группу if options.has_key('a'): # добавляемые пользователи в группу users = options['a'].split(',') res = self.addUsersGroupMail(users, groupName) if res: self.printSUCCESS(_("Appended list users to group") + " " +\ str(groupName)) else: self.printERROR(_("Can not append list users to group") +\ " " + str(groupName)) return False # Удаляем список пользователей из группы if options.has_key('d'): # удаляемые пользователи из группы users = options['d'].split(',') res = self.delUsersGroupMail(users, groupName) if res: self.printSUCCESS(_("Deleted list users from group") + " " +\ str(groupName)) else: self.printERROR(_("Can not delete list users from group") +\ " " + str(groupName)) return False # Изменяем имя группы modGroupName = groupName if options.has_key('n'): newGroupName = options['n'] if self.searchMailGroupToName(newGroupName): self.printERROR( _("group name %s is found in Mail service")%\ str(newGroupName)) return False # изменяем адрес и альтернативный адрес altEmails = searchGroup[0][0][1]["mailAlternateAddress"] for altEmail in altEmails: splAltEmail = altEmail.split("@") grName = splAltEmail[0] if groupName == grName: altEmailDomen = "" if len(splAltEmail)==2: altEmailDomen = splAltEmail[1] newAltEmail = "%s@%s" %(newGroupName,altEmailDomen) attrDelete.append( (ldap.MOD_DELETE, 'mailAlternateAddress', altEmail)) attrAppend.append( (ldap.MOD_ADD, 'mailAlternateAddress', newAltEmail)) break email = searchGroup[0][0][1]["mail"][0] splEmail = email.split("@") emailDomen = "" if len(splEmail)==2: emailDomen = splEmail[1] newEmail = "%s@%s" %(newGroupName,emailDomen) attrAppend.append((ldap.MOD_REPLACE, 'mail', newEmail)) attrAppend.append((ldap.MOD_REPLACE, 'mailMessageStore', newGroupName + "/")) newFirstDn = "cn=" + newGroupName oldDN = self.addDN("cn=" + groupName, self.relGroupsDN) res = self.modifyElemDN(oldDN, newFirstDn) # Меняем название реплицируемого алиаса if servReplObj: if not servReplObj.renameReplMailAlias(groupName, newGroupName): self.printERROR(_("Failed modify name '%s' mail alias \ in 'Replication/Mail' branch") %groupName) return False if res: self.printSUCCESS(_("Group renamed to %s")\ %newGroupName) modGroupName = newGroupName else: self.printERROR(_("Can not rename group")) return False modAttrs = attrDeleteFirst + attrAppend + attrDelete # Изменяем комментарий к группе if options.has_key('c'): gecos = options['c'] modAttrs.append((ldap.MOD_REPLACE, 'description', gecos)) if not modAttrs: if options.has_key('hide-off'): self.printWARNING(\ _("Hide mail hosts have already been deleted")) return True if modAttrs: groupDN = self.addDN("cn=" + modGroupName, self.relGroupsDN) res = self.modAttrsDN(groupDN, modAttrs) if res: if options.has_key('c'): self.printSUCCESS(_("Modified group comment")) if options.has_key('e'): self.printSUCCESS(_("Modified mail alternate address")) if options.has_key('hide'): self.printSUCCESS(_("Modified hide mail hosts")) if options.has_key('hide-off'): self.printSUCCESS(_("Deleted hide mail hosts")) return True else: if options.has_key('c'): self.printERROR(_("Can not modify group comment")) if options.has_key('e'): self.printERROR(_("Can not modify mail alternate address")) if options.has_key('hide'): self.printERROR(_("Can not modify hide mail hosts")) if options.has_key('hide-off'): self.printERROR(_("Can not delete hide mail hosts")) return False return True def modUserMailServer(self, userName, options): """Модифицирует настройки пользователя Mail в LDAP""" # Проверим установлен ли сервис Mail if not self.initialChecks("mail"): return False res = self.searchMailUserToName(userName) if not res: self.printERROR( _("User %s is not found in Mail service")%\ str(userName)) return False # Новые группы в которые входит пользователь if options.has_key('G'): userGroups = options['G'].split(',') #список имен добавляемых групп userGroupNames = self.searchGroupsMail(userGroups) if not userGroupNames: return False # Удаляем пользователя из групп в которые он входит if not self.delUserInGroup(userName): return False flagError = False for group in userGroupNames: if not self.addUsersGroupMail([userName], group): flagError = True break if flagError: return False self.printSUCCESS(_("Replaced list of supplementary group")) # Добавляем группы в которые входит пользователь elif options.has_key('a'): userGroups = options['a'].split(',') #список имен добавляемых групп userGroupNames = self.searchGroupsMail(userGroups) if not userGroupNames: return False flagError = False for group in userGroupNames: if not self.addUsersGroupMail([userName], group): flagError = True break if flagError: return False self.printSUCCESS(_("Appended list of supplementary group")) # Изменяемые аттрибуты пользователя modAttrs = [] # Включаем пользователя if options.has_key('U'): modAttrs += [(ldap.MOD_REPLACE, 'accountStatus', "active")] # Выключаем пользователя elif options.has_key('L'): modAttrs += [(ldap.MOD_REPLACE, 'accountStatus', "passive")] # Изменяем комментарий к пользователю if options.has_key('c'): comment = options['c'] modAttrs += [(ldap.MOD_REPLACE, 'sn', comment), (ldap.MOD_REPLACE, 'cn', comment)] # Изменяем пароль пользователя userPwd = self.getUserPassword(options, "p", "P") if userPwd == False: return False if userPwd: userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) if not userPwdHash: return False if res[0][0][1].has_key('userPassword'): modAttrs.append((ldap.MOD_REPLACE, 'userPassword', userPwdHash)) else: modAttrs.append((ldap.MOD_ADD, 'userPassword', userPwdHash)) # Заменяем альтернативные почтовые адреса # Первичный почтовый адрес primaryMail = "" altMails = [] if options.has_key('e'): altEmails = res[0][0][1]["mailAlternateAddress"] altMails = options['e'].split(",") for altMail in altMails: if "@" in altMail: if len(altMail.split("@")) != 2: self.printERROR(_("Incorrect alternate adresses \ option '-e'")) return False mail = altMail else: mail = "%s@%s" %(altMail,self.clVars.Get("sr_mail_host")) if not primaryMail: primaryMail = mail searchUserMail = self.searchUserToMail(mail) if self.searchGroupToMail(mail) or (searchUserMail and\ (not (mail in altEmails) and len(searchUserMail) == 1 or\ len(searchUserMail) != 1)): self.printERROR( _("Alternate email address %s is found in Mail service")%\ str(mail)) return False modAttrs.append((ldap.MOD_ADD, 'mailAlternateAddress', mail)) # Удаляем предыдущие адреса self.delAlternateAddress(userName) # Изменяем основной почтовый адрес if primaryMail: if not self.servUnixObj.setUserMail(userName, primaryMail): self.printERROR(_("Failed set primary email for user %s \ in Unix service") %str(primaryMail)) return False # Если включена репликация почты if self.clVars.Get("ld_repl_mail_set") == "on": # Объект сервис репликации servReplObj = servRepl() if altMails: for mail in altMails: if "@" in altMail: mail = altMail else: mail = "%s@%s" %(altMail,\ self.clVars.Get("sr_mail_host")) foundReplAlias = servReplObj.searchMailAddress(mail) if foundReplAlias: flagError = False foundReplUsers = foundReplAlias[0][0][1]['cn'] for foundReplUser in foundReplUsers: if foundReplUser!=userName: flagError = True break if flagError: self.printERROR(_("Mail address %s is found in \ 'Replication/Mail' branch")%mail) self.printERROR(_("The address belongs to \ mail user or group: %s")%foundReplUser) return False if not servReplObj.modReplMailAlias(userName, altMails): self.printERROR(_("Failed modify mail aliases \ for user %s in 'Replication/Mail' branch") %userName) return False if modAttrs: DN = self.addDN("uid="+userName, self.relUsersDN) if not self.modAttrsDN(DN, modAttrs): return False if options.has_key('c'): self.printSUCCESS(_("Modified comment")) if options.has_key('L'): self.printSUCCESS(_("Locked Mail user %s")%str(userName)) if options.has_key('U'): self.printSUCCESS(_("Unlocked Mail user %s")%str(userName)) if options.has_key('e'): self.printSUCCESS(_("Modified Mail alternate addresses")) if options.has_key('P') or options.has_key('p'): self.printSUCCESS(_("Modified Mail user password")) return True @adminConnectLdap def addGroupMailServer(self, groupName, options): """Добавляет группу пользователей Mail""" # Проверим установлен ли сервис Mail if not self.initialChecks("mail"): return False # Проверяем на включение почтовой репликации servReplObj = False if self.clVars.Get("ld_repl_mail_set") == "on": # Объект сервис репликации servReplObj = servRepl() if servReplObj.searchMailAlias(groupName): self.printERROR(_("Mail group %s is found in \ 'Replication/Mail' branch")%groupName) return False #Проверяем альтернативные почтовые адреса modAttrs = [] altMails = [] if options.has_key('e'): altMails = options['e'].split(",") for altMail in altMails: if "@" in altMail: if len(altMail.split("@")) != 2: self.printERROR(_("Incorrect alternate adresses \ option '-e'")) return False mail = altMail else: mail = "%s@%s" %(altMail,self.clVars.Get("sr_mail_host")) if self.searchUserToMail(mail) or\ self.searchGroupToMail(mail): self.printERROR( _("Alternate email address %s is found in Mail service")%\ str(mail)) return False if servReplObj: foundReplAlias = servReplObj.searchMailAddress(mail) if foundReplAlias: foundReplUser = foundReplAlias[0][0][1]['cn'][0] self.printERROR(_("Mail address %s is found in \ 'Replication/Mail' branch")%mail) self.printERROR(_("The address belongs to \ mail user or group: %s")%foundReplUser) return False modAttrs.append('mailAlternateAddress: %s' %mail) # Фильтр почты (hostname) fHostNames = [] if options.has_key('hide'): fHostNames = options['hide'].split(",") for fHostName in fHostNames: if not "." in fHostName: fHostName = "%s.%s" %(fHostName, self.clVars.Get('os_net_domain')) modAttrs.append('filtersender: %s' %fHostName) if self.searchMailGroupToName(groupName): self.printERROR( _("group name %s is found in Mail service")%\ str(groupName)) return False mail = "%s@%s" %(groupName,self.clVars.Get("sr_mail_host")) if self.searchUserToMail(mail) or\ self.searchGroupToMail(mail): self.printERROR( _("Email address %s is found in Mail service")%\ str(mail)) return False if servReplObj: foundReplAlias = servReplObj.searchMailAddress(mail) if foundReplAlias: foundReplUser = foundReplAlias[0][0][1]['cn'][0] self.printERROR(_("Mail address %s is found in \ 'Replication/Mail' branch")%mail) self.printERROR(_("The address belongs to \ mail user or group: %s")%foundReplUser) return False self.clVars.Set("ur_group", groupName) # Комментарий к группе groupGecos = self.servUnixObj.groupGecos if options.has_key('c'): groupGecos = options['c'] self.clVars.Set("ur_group_comment",groupGecos) ldifFile = self.ldifFileGroup groupRawLdif = self.createLdif(ldifFile) if not groupRawLdif: print self.getError() return False groupLdif = groupRawLdif.rstrip() + "\n" + "\n".join(modAttrs) if not self.ldapObj.getError(): self.ldapObj.ldapAdd(groupLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False if servReplObj: # Записываем почтовые алиасы в ветку # репликации Replication/Mail if altMails and not servReplObj.addReplMailAlias(groupName, altMails, fHostNames): self.printERROR(_("Failed set mail aliases \ for user %s in 'Replication/Mail' branch") %str(primaryMail)) return False self.printSUCCESS(_("Added group '%s' in Mail service")\ %groupName) return True def modUserMailPasswd(self, userName, options): """Устанавливает пароль Mail пользователя и меняет его опции""" # Проверим установлен ли сервис Mail if not self.initialChecks("mail"): return False res = self.searchMailUserToName(userName) if not res: self.printERROR( _("User %s is not found in Mail service") % str(userName)) return False # Изменяемые аттрибуты пользователя modAttrs = [] # Включаем пользователя if options.has_key('u'): modAttrs += [(ldap.MOD_REPLACE, 'accountStatus', "active")] # Выключаем пользователя elif options.has_key('l'): modAttrs += [(ldap.MOD_REPLACE, 'accountStatus', "passive")] if not options: optPasswd = {"p":""} userPwd = self.getUserPassword(optPasswd, "p", False) if userPwd == False: return False userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) if not userPwdHash: return False if res[0][0][1].has_key('userPassword'): modAttrs.append((ldap.MOD_REPLACE, 'userPassword', userPwdHash)) else: modAttrs.append((ldap.MOD_ADD, 'userPassword', userPwdHash)) if modAttrs: DN = self.addDN("uid="+userName, self.relUsersDN) if not self.modAttrsDN(DN, modAttrs): return False if options.has_key('l'): self.printSUCCESS(_("Locked Mail user %s")% str(userName)) if options.has_key('u'): self.printSUCCESS(_("Unlocked Mail user %s")% str(userName)) if not options: self.printSUCCESS(_("Changed Mail user password")) return True return False def searchUsersInGroupMail(self, usersNames, groupName): """Ищет спиcок пользователей в группе, ищет в LDAP В случае успеха выводит список найденных пользователей если нет группы False если ничего не найдено пустой список """ res = self.searchMailGroupToName(groupName) if not res: return False else: findUsers = [] if res[0][0][1].has_key('rfc822member'): usersInGroup = res[0][0][1]['rfc822member'] for userName in usersNames: userMail = "%s@%s" %(userName, self.clVars.Get("sr_mail_host")) if userMail in usersInGroup: findUsers.append(userName) return findUsers def searchMailUserToName(self, userName): """Находит пользователя сервиса Mail по имени""" resSearch = self.searchLdapDN(userName, self.relUsersDN, "uid") return resSearch def searchUserToMail(self, mail): """Находит пользователя по почтовому адресу в сервисе Mail""" resSearch = self.searchLdapDN(mail, self.relUsersDN, "mail") if not resSearch: resSearch = self.searchLdapDN(mail, self.relUsersDN, "mailAlternateAddress") return resSearch def searchMailUser(self, nameOrMali): """Находит пользователя сервиса Mail по имени или email""" if "@" in nameOrMali: resSearch = self.searchUserToMail(nameOrMali) else: resSearch = self.searchMailUserToName(nameOrMali) return resSearch def searchGroupToMail(self, mail): """Находит группу по ее почтовому адресу""" resSearch = self.searchLdapDN(mail, self.relGroupsDN, "mail") if not resSearch: resSearch = self.searchLdapDN(mail, self.relGroupsDN, "mailAlternateAddress") return resSearch def createMailDir(self, userName, uid, gid): """Создание пользовательской директории для почты""" def createCNT(mailDir, uid, gid): """создание cur, new, tmp в текущей директории""" appendDirs = ["cur","new","tmp"] flagError = False for appDir in appendDirs: createDir = os.path.join(mailDir, appDir) if not self.createUserDir(uid, gid, createDir, False): flagError = True break if flagError: return False return True mailDir = os.path.join(self.clVars.Get("sr_mail_path"), userName) flagError = False if not self.createUserDir(uid, gid, mailDir): flagError = True if not flagError and not createCNT(mailDir, uid, gid): flagError = True if not flagError: mailDirs = [os.path.join(mailDir,".Drafts"), os.path.join(mailDir,".Sent"), os.path.join(mailDir,".Spam"), os.path.join(mailDir,".Trash")] for createDir in mailDirs: if not self.createUserDir(uid, gid, createDir, False): flagError = True break if not createCNT(createDir, uid, gid): flagError = True break if flagError: return False return True def addUsersGroupMail(self, users, groupName): """Добавляет пользователей из списка в Mail группу""" # Проверим установлен ли сервис Mail if not self.initialChecks("mail"): return False if not self.searchMailGroupToName(groupName): self.printERROR(_("Group name is not found in Mail service")) return False flagFalse = False for userName in users: if not self.searchMailUserToName(userName): self.printERROR( _("User %s is not found in Mail service")%\ str(userName)) flagFalse = True break if flagFalse: return False foundUsersMail = self.searchUsersInGroupMail(users, groupName) foundUsers = [] if foundUsersMail: foundUsers = foundUsersMail addUsers = [] for user in users: if not(user in foundUsers): addUsers.append(user) modAttrs = [] for userName in addUsers: userMail = "%s@%s" %(userName,self.clVars.Get("sr_mail_host")) modAttrs.append((ldap.MOD_ADD, 'rfc822member', userMail)) if modAttrs: groupDN = self.addDN("cn="+groupName, self.relGroupsDN) return self.modAttrsDN(groupDN, modAttrs) return True def delUserInMailAndUnix(self, userName, flagDelUnixUser): """Удаляет пользователя без бекапа Удаляет из Mail и если установлен флаг из Unix """ if not self.delUserMailServer(userName, {}, False,False): return False if flagDelUnixUser: if not self.servUnixObj.delUserUnixServer(userName, {}, False, False): return False return True @adminConnectLdap def addUserMailServer(self, userName, options): """Добавляет почтового пользователя в LDAP-сервер""" # Проверим установлен ли сервис Mail if not self.initialChecks("mail"): return False # Проверяем на включение почтовой репликации servReplObj = False if self.clVars.Get("ld_repl_mail_set") == "on": # Объект сервис репликации servReplObj = servRepl() if servReplObj.searchMailAlias(userName): self.printERROR(_("Mail user %s is found in \ 'Replication/Mail' branch")%userName) return False #Проверяем альтернативные почтовые адреса modAttrs = [] primaryMail = "" altMails = [] if options.has_key('e'): altMails = options['e'].split(",") for altMail in altMails: if "@" in altMail: if len(altMail.split("@")) != 2: self.printERROR(_("Incorrect alternate adresses option \ '-e'")) return False mail = altMail else: mail = "%s@%s" %(altMail,self.clVars.Get("sr_mail_host")) if not primaryMail: primaryMail = mail if self.searchUserToMail(mail) or\ self.searchGroupToMail(mail): self.printERROR(\ _("Alternate email address %s is found in Mail service")%\ str(mail)) return False if servReplObj: foundReplAlias = servReplObj.searchMailAddress(mail) if foundReplAlias: foundReplUser = foundReplAlias[0][0][1]['cn'][0] self.printERROR(_("Mail address %s is found in \ 'Replication/Mail' branch")%mail) self.printERROR(_("The address belongs to \ mail user or group: %s")%foundReplUser) return False modAttrs.append("mailAlternateAddress: %s" %mail) else: self.printERROR(\ _("Must be added one or more alternative addresses")) self.printWARNING("cl-useradd -e gst@calculate.org guest mail") return False if self.searchMailUserToName(userName): self.printERROR(_("User exists in Mail service")) return False else: mail = "%s@%s" %(userName,self.clVars.Get("sr_mail_host")) if self.searchUserToMail(mail) or\ self.searchGroupToMail(mail): self.printERROR( _("Email address %s is found in Mail service")%\ str(mail)) return False if servReplObj: foundReplAlias = servReplObj.searchMailAddress(mail) if foundReplAlias: foundReplUser = foundReplAlias[0][0][1]['cn'][0] self.printERROR(_("Mail address %s is found in \ 'Replication/Mail' branch")%mail) self.printERROR(_("The address belongs to \ mail user or group: %s")%foundReplUser) return False # Почтовая директория пользователя mailDir = os.path.join(self.clVars.Get("sr_mail_path"), userName) # Поиск почтовой директории пользователя if os.path.exists(mailDir): self.printERROR(_("Path %s exists") %mailDir) return False resUnix = self.servUnixObj.searchUnixUser(userName) resPwd = self.servUnixObj.searchPasswdUser(userName) # Пароль пользователя почты userPwd = self.getUserPassword(options, "p", "P") if userPwd == False: return False flagCreateUnixUser = False if not (resUnix or resPwd): flagCreateUnixUser = True # Добавим пользователя LDAP optUnix = {} # Флаг создания группы по умолчанию flagCreateUnixGroup = False # Группа пользователя if options.has_key('g'): optUnix['g'] = options['g'] else: optUnix['g'] = self.defaultUnixGroup["name"] # Проверяем необходимость переименовывания группы oldGroupName = "mail domain" if self.servUnixObj.searchUnixGroupName(oldGroupName) and\ not self.servUnixObj.searchUnixGroupName(optUnix['g']): # Переименовываем группу if not self.servUnixObj.modGroupUnixServer(oldGroupName, {'n':optUnix['g']}, False): return False # Проверяем существование группы if not self.servUnixObj.searchUnixGroupName(optUnix['g']): flagCreateUnixGroup = True # Полное имя пользователя if options.has_key('c'): optUnix['c'] = options['c'] # Если нужно создаем новую Unix группу if flagCreateUnixGroup: unixGroupFullName = self.defaultUnixGroup["comment"] optGroupUnix = {"c": unixGroupFullName} if not self.servUnixObj.addGroupUnixServer(optUnix['g'], optGroupUnix, False): self.printERROR (_("Can not add group")+ " " +\ str(optUnix['g']) + _(" in Unix service")) return False if not self.servUnixObj.addUserUnixServer(userName, optUnix, False): self.printERROR (_("Can not add user")+ " " +\ str(userName) + _(" in Unix service")) return False resUnix = self.servUnixObj.searchUnixUser(userName) self.clVars.Set("ur_name", userName) #Полное имя пользователя fullNameUser = self.servUnixObj.fullNameUser if options.has_key('c'): fullNameUser = options['c'] else: if resUnix and resUnix[0][0][1].has_key('cn'): fullNameUser = resUnix[0][0][1]['cn'][0] self.clVars.Set("ur_fio",fullNameUser) if not userPwd: userPwdHash = "crypt{xxx}" else: userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) if not userPwdHash: if flagCreateUnixUser: self.servUnixObj.delUserUnixServer(userName, {}, False, False) return False self.clVars.Set("ur_hash",userPwdHash) ldifFile = self.ldifFileUser userRawLdif = self.createLdif(ldifFile) if not userRawLdif: print self.getError() if flagCreateUnixUser: self.servUnixObj.delUserUnixServer(userName, {}, False, False) return False userLdif = userRawLdif.rstrip() + "\n" + "\n".join(modAttrs) if not self.ldapObj.getError(): #Добавляем пользователя в LDAP self.ldapObj.ldapAdd(userLdif) #ldapObj.ldapAdd(userLdif1) # не переделывать на else flagError = False if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() flagError = True if not flagError: if resUnix: uid = int(resUnix[0][0][1]['uidNumber'][0]) gid = int(resUnix[0][0][1]['gidNumber'][0]) elif resPwd: uid = int(resPwd.split(":")[2]) gid = int(resPwd.split(":")[3]) else: self.printERROR(_("user are not found")) flagError = True if not flagError: # Востановим удаленного пользователя message = _("Do you want to restore deleted user %s data?")\ %userName + "\n" + "'yes', 'no'" resMailDir = self.restorePathDelUser(userName, mailDir, "mail", message) removeMailDirBack = False if not resMailDir: flagError = True createDirMail = False else: term, createDirMail, removeMailDirBack = resMailDir # Создаем почтовую директорию if not flagError and createDirMail: if not self.createMailDir(userName, uid, gid): flagError = True # Записываем основной почтовый адрес if not flagError and primaryMail: # Записываем основной почтовый адрес в ветку Unix if not self.servUnixObj.setUserMail(userName, primaryMail): self.printERROR(_("Failed set primary email for user %s in \ Unix service") %str(primaryMail)) flagError = True # Записываем почтовые алиасы в ветку # репликации Replication/Mail if not flagError and servReplObj: if not servReplObj.addReplMailAlias(userName, altMails): self.printERROR(_("Failed set mail aliases \ for user %s in 'Replication/Mail' branch") %userName) flagError = True if not flagError and removeMailDirBack\ and os.path.exists(removeMailDirBack): self.removeDir(removeMailDirBack) self.removeEmptyDir(os.path.split(removeMailDirBack)[0]) if flagError: self.delUserInMailAndUnix(userName, flagCreateUnixUser) self.printERROR(_("Can not add user")) return False if flagCreateUnixUser: self.printSUCCESS(_("Added user in Unix service")) self.printSUCCESS(_("Added user in Mail service")) return True def getAllowNet(self): """Получаем от пользователя доверительные сети и устанавливаем переменную профилей sr_mail_net_allow self.clVars должен быть определен """ print _("Enter the allowed ip addresses and network for %s service")\ %"Mail" + " (" + _("comma or space delimited") + ")" strPrompt = _("allow networks: ") netAllow = self.clVars.Get("sr_mail_net_allow") strNetAllow = "" if netAllow: strNetAllow = netAllow.replace(","," ") allowNet = self.getUserAllowNetwork(strPrompt, strNetAllow) if not allowNet: return False # Установка переменной доступные сети allowNet = ",".join(allowNet) self.clVars.Set("sr_mail_net_allow", allowNet ,True) return allowNet def getHostName(self): """Получаем от пользователя имя почтового хоста и устанавливаем переменную профилей sr_mail_host self.clVars должен быть определен """ def correctHostname(hostname): # Проверяет корректность введенного имени хоста reCorrect = re.compile(\ "([A-Za-z0-9]\.|[A-Za-z0-9][-A-Za-z0-9]{0,61}[-A-Za-z0-9](\.|$))*") correctHost = hostname.strip() findHost = reCorrect.search(correctHost) if findHost and findHost.group() == correctHost: return correctHost return False def printW(): print _("Incorrect string hostname") print _("Try again\n") print _("Enter the hostname for %s service")%"Mail" strPrompt = _("hostname: ") hostname = self.clVars.Get("sr_mail_host") hostname = self.raw_input(strPrompt, hostname) i = 0 while i<3 and not correctHostname(hostname): printW() hostname = self.raw_input(strPrompt, hostname) i += 1 if i == 3 and not correctHostname(hostname): printW() self.printERROR(_("You used four attempts, \ if you want to continue to run the program again")) return False # Установка имени хоста fullHostName = correctHostname(hostname) if not "." in fullHostName: fullHostName = "%s.%s" %(fullHostName, self.clVars.Get('os_net_domain')) self.clVars.Set("sr_mail_host", fullHostName, True) return True def addDefaultMailGroup(self): """Add default mail group to unix""" mailGroup = self.defaultUnixGroup["name"] if not self.servUnixObj.searchUnixGroupName(mailGroup): # Если нужно создаем новую Unix группу unixGroupFullName = self.defaultUnixGroup["comment"] optGroupUnix = {"c": unixGroupFullName} if not self.servUnixObj.addGroupUnixServer(mailGroup, optGroupUnix, False): self.printERROR (_("Can not add group")+ " " +\ str(mailGroup) + _(" in Unix service")) return False return True def setupMailServer(self, options): """Начальная настройка Mail сервиса""" # Принудительная установка forceOptions = False if options.has_key("f"): forceOptions = True # Создаем объект переменных и начальная проверка if not self.initialChecksSetup(): return False if self.clVars.Get("sr_unix_set") != "on": self.printERROR(_("Unix service is not setuped")) self.printWARNING(_("Setup Unix service")) self.printWARNING(" cl-setup unix") return False # Доверительные сети по умолчанию allowNet = self.clVars.Get("os_net_allow") # В случае если сервер установлен if self.clVars.Get("sr_mail_set") == "on" and\ not forceOptions: self.printWARNING (_("WARNING") + ": " +\ _("Mail server is configured")+ ".") return True if not forceOptions: # предупреждение при выполнении этой программы будут изменены # конфигурационные файлы сервиса Mail (программы Postfix и Dovecot) self.printWARNING (_("WARNING") + ": " + _("Executing of the program will change") + " " + _("the configuration files of Mail service") +" ("+ _("programs Postfix and Dovecot") + ")." ) # если вы готовы продолжить работу программы нажмите Y если нет n messDialog = \ _("If you are ready to continue executing the program") + ", "+\ _("input 'yes'") +", "+ _("if not 'no'") if not self.dialogYesNo(messDialog): return True if options.has_key("a"): # Получаем от пользователя доверительные сети allowNet = self.getAllowNet() if not allowNet: return False else: if options.has_key("a"): # Получаем от пользователя доверительные сети allowNet = self.getAllowNet() if not allowNet: return False # делаем backup # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False bakupObj = servLdap() if not bakupObj.backupServer(): return False # Удаляем переменные сервиса в ini файлах self.deleteServiceVarsInFile("mail") # Cоздаем объект переменные self.createClVars() # Объект сервис репликации servReplObj = servRepl() foundReplication = False # проверяем на присутствие серверов репликации for replServ in servReplObj.replServices: if self.clVars.Get("ld_repl_%s_servers"%replServ): foundReplication = True break if not foundReplication: # Если серверов репликации нет # удаляем переменные репликации servReplObj.clVars = self.clVars servReplObj.deleteVars() # Cоздаем объект переменные self.createClVars() # Устанавливаем доступные сети self.clVars.Set("sr_mail_net_allow",allowNet,True) # Удаляем из автозапуска демона if not self.delDaemonAutostart("postfix"): return False # Удаляем из автозапуска демона if not self.delDaemonAutostart("dovecot"): return False # останавливаем сервис Mail if not self.stopServices(["mail"]): return False # Имя устанавливаемого сервиса self.clVars.Set("cl_pass_service","mail") self.clVars.Write("sr_mail_set","off") # Почтовый ност fullHostName = "%s.%s"%(self.clVars.Get('os_net_hostname'), self.clVars.Get('os_net_domain')) if options.has_key("host"): fullHostName = options['host'] if not "." in fullHostName: fullHostName = "%s.%s" %(fullHostName, self.clVars.Get('os_net_domain')) self.clVars.Set("sr_mail_host",fullHostName,True) history,history_domain,history_path = self.getMailHistoryData(options) mailType = "imap" if options.has_key("t"): mailType = options['t'] if mailType: if not set(mailType.split(",")) <= set(["imap","pop3"]): self.printERROR(\ _("Мail type not 'imap' or 'pop3' or 'pop3,imap'")) return False if len(mailType.split(",")) == 2: mailType = "all" else: self.printERROR(_("Мail type incorrect")) return False self.clVars.Set("sr_mail_type", mailType) mailCrypt = "tls" if options.has_key("c"): mailCrypt = options['c'] if not mailCrypt in ["none", "tls"]: self.printERROR(_("Мail encryption not 'none' or 'tls'")) return False if mailCrypt == "none": mailCrypt = "" self.clVars.Set("sr_mail_crypt", mailCrypt, True) if not self.applyProfilesFromService('mail'): return False if not self.createMailCertificate(): return False # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False else: if not self.restartLdapServer(): return False # Подключаемся к LDAP cерверу if not shareLdap.getLdapObjInFile(self): return False # Находим в LDAP Mail сервис resSearch = self.searchService() if resSearch: delDN = self.relDN if self.deleteDN(delDN): self.printOK(_("Remove Mail DN from LDAP Database") + " ...") else: self.printERROR(_("Can not remove Mail DN from LDAP Database")) return False # в случае отключения репликации if self.clVars.Get("ld_repl_set") != "on": # Объект сервис репликации servReplObj = servRepl() # Удаляем служебную ветку ldap if not servReplObj.delSysDN(): return False ldifFile = self.ldifFileBase baseLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): self.ldapObj.ldapAdd(baseLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False # Записываем данные администратора сервиса Mail ldapParser = iniLdapParser() ldapParser.setVar("mail", {"DN":self.clVars.Get("ld_mail_dn"), "PASS":self.clVars.Get("ld_mail_pw")}) self.printOK(_("Added ldif file") + " ...") textLine = self.execProg("newaliases") if textLine == False: self.printERROR(_("Can not create Postfix aliases")) return False if history == "on": msgStartSort = _("Starting") + " " + "Sortmilter" + " ..." if self.execProg("/etc/init.d/sortmilter start") == False: self.printNotOK(msgStartSort) return False else: self.printOK(msgStartSort) if not self.addDefaultMailGroup(): return False textLines = self.execProg("/etc/init.d/postfix start") if textLines == False: self.printNotOK(_("Starting") + " " + "Postfix" + " ...") return False else: self.printOK(_("Starting") + " " + "Postfix" + " ...") textLines = self.execProg("/etc/init.d/dovecot start") if textLines == False: self.printNotOK(_("Starting") + " " + "Dovecot" + " ...") return False else: self.printOK(_("Starting") + " " + "Dovecot" + " ...") # Устанавливаем автозапуск демона if not self.setDaemonAutostart("postfix"): return False # Устанавливаем автозапуск демона if not self.setDaemonAutostart("dovecot"): return False # Устанавливаем автозапуск демона sortmilter if history == "on" and not self.setDaemonAutostart("sortmilter"): return False #запишем переменные для сервера mailHost = self.clVars.Get("sr_mail_host") self.clVars.Write("sr_mail_host",mailHost,True,"local") self.clVars.Write("sr_mail_type", self.clVars.Get("sr_mail_type"),True,"local") self.clVars.Write("sr_mail_crypt", self.clVars.Get("sr_mail_crypt"),True,"local") self.clVars.Write("sr_mail_net_allow", self.clVars.Get("sr_mail_net_allow"),True,"local") self.clVars.Write("sr_mail_history", self.clVars.Get("sr_mail_history"), True,"local") self.clVars.Write("sr_mail_history_path", self.clVars.Get("sr_mail_history_path"), True,"local") self.clVars.Write("sr_mail_history_domain", self.clVars.Get("sr_mail_history_domain"), True,"local") #запишем переменные для клиента if mailType == "all": self.clVars.Set("sr_mail_type","imap") self.clVars.Set("sr_mail_send_host",mailHost) clientVars = ["sr_mail_host","sr_mail_crypt", "sr_mail_port", "sr_mail_type","sr_mail_send_crypt","sr_mail_send_port", "sr_mail_send_host"] if not self.saveVarsClient(clientVars): return False self.clVars.Write("sr_mail_set","on") self.printOK(_("Mail service configured") + " ...") return True class servJabber(shareLdap): """Методы сервиса Jabber""" relGrDN = 'ou=Groups' relUsDN = 'ou=Users' relServDN = 'ou=Jabber' ldifFileBase = "/usr/lib/calculate/calculate-server/ldif/jabber_base.ldif" ldifFileUser = "/usr/lib/calculate/calculate-server/ldif/jabber_user.ldif" ldifFileGroup = "/usr/lib/calculate/calculate-server/ldif/jabber_group.ldif" def __init__(self, unixObj=False): shareLdap.__init__(self) # DN сервиса self.relDN = self.addDN(self.relServDN,self.ServicesDN) # DN пользователей, относительно базового DN self.relUsersDN = self.addDN(self.relUsDN, self.relDN) # DN групп пользователей, относительно базового DN self.relGroupsDN = self.addDN(self.relGrDN, self.relDN) if unixObj: # получаем объект сервиса Unix self.servUnixObj = unixObj else: # создаем объект сервиса Unix self.servUnixObj = servUnix() def searchGroupToName(self, groupName): """Находит группу сервиса Jabber по её имени""" resSearch = self.searchLdapDN(groupName, self.relGroupsDN, "cn") return resSearch def searchUserToId(self, jabberId): """Находит пользователя по Jabber ID в сервисе Jabber""" resSearch = self.searchLdapDN(jabberId, self.relUsersDN, "mail") return resSearch def searchUserToName(self, name): """Находит пользователя по имени в сервисе Jabber""" resSearch = self.searchLdapDN(name, self.relUsersDN, "uid") return resSearch def searchUsersToGroup(self, descr): """Находит пользователей по description""" resSearch = self.searchLdapDN(descr, self.relUsersDN, "departmentNumber") return resSearch def searchAllUsers(self): """Находит у всех пользователей uid и JabberID""" resSearch = self.searchLdapDN("*", self.relUsersDN, "uid",["uid", "cn", "mail"]) return resSearch def searchUsersToHostName(self, hostName): """Находит всех пользователей с данным именем хоста""" resSearch = self.searchLdapDN("*@%s" %hostName, self.relUsersDN, "mail",["uid", "mail"]) return resSearch def searchUserToNameOrId(self, nameOrId): """Находит пользователя сервиса Jabber по имени или id""" resSearch = self.searchUserToName(nameOrId) if resSearch: return resSearch resSearch = self.searchUserToId(nameOrId) return resSearch def setUserGroup(self, userName, groupName, userS=False, groupS=False): """Устанавливает Jabber группу для пользователя""" if groupS: groupSearch = groupS else: groupSearch = self.searchGroupToName(groupName) if not groupSearch: self.printERROR(_("Group name is not found in Jabber service")) return False if userS: userSearch = userS else: userSearch = self.searchUserToNameOrId(userName) if not userSearch: self.printERROR(_("User %s is not found in Jabber service")%\ str(userName)) return False modAttrs = [] descr = groupSearch[0][0][1]["cn"][0] uid = userSearch[0][0][1]["uid"][0] if userSearch[0][0][1].has_key('departmentNumber'): modAttrs.append((ldap.MOD_REPLACE, 'departmentNumber', descr)) else: modAttrs.append((ldap.MOD_ADD, 'departmentNumber', descr)) userDN = self.addDN("uid="+uid, self.relUsersDN) return self.modAttrsDN(userDN, modAttrs) def renameJabberId(self, userName, newJabberId): """Изменяет jabber ID для пользователя""" searchUser = self.searchUserToName(userName) if not searchUser: self.printERROR(_("User %s is not found in Jabber service")%\ str(userName)) return False modAttrs = [] if searchUser[0][0][1].has_key('mail'): modAttrs.append((ldap.MOD_REPLACE, 'mail', newJabberId)) else: modAttrs.append((ldap.MOD_ADD, 'mail', newJabberId)) userDN = self.addDN("uid="+userName, self.relUsersDN) return self.modAttrsDN(userDN, modAttrs) @adminConnectLdap def setHostName(self, newHostName, oldHostName): """Заменяет пользователям имя хоста на новое""" searchUsers = self.searchUsersToHostName(oldHostName) if not searchUsers: self.printWARNING(_("Host name %s not found in Jabber service")\ %oldHostName) return True flagError = False for userFields in searchUsers: newJabberId = userFields[0][1]['mail'][0].replace(oldHostName, newHostName) userName = userFields[0][1]['uid'][0] if not self.renameJabberId(userName, newJabberId): self.printERROR(_("Can not change host name for user %s \ in Jabber service")) flagError = True break if flagError: return False return True def addUsersGroupJabber(self, users, groupName, replaceFlag=False): """Добавляет пользователей из списка в Jabber группу""" groupSearch = self.searchGroupToName(groupName) if not groupSearch: self.printERROR(_("Group name is not found in Jabber service")) return False flagFalse = False for userName in users: userSearch = self.searchUserToNameOrId(userName) if not userSearch: self.printERROR(_("User %s is not found in Jabber service")%\ str(userName)) flagFalse = True break if not replaceFlag and\ userSearch[0][0][1].has_key('departmentNumber'): self.printERROR(_("User %s is found in group")%\ str(userName) + " " + str(groupName)) flagFalse = True break if flagFalse: return False for userName in users: if not self.setUserGroup(userName, groupName): flagFalse = True break if flagFalse: return False return True def delUsersGroupJabber(self, users, groupName): """Удаляет пользователей из списка в Jabber группе""" groupSearch = self.searchGroupToName(groupName) if not groupSearch: self.printERROR(_("Group name is not found in Jabber service")) return False flagFalse = False res = True for userName in users: userSearch = self.searchUserToNameOrId(userName) if userSearch and userSearch[0][0][1].has_key('departmentNumber'): if not userSearch[0][0][1]['departmentNumber'][0] == \ groupSearch[0][0][1]['cn'][0]: self.printERROR(_("User %s is not found in group")%\ str(userName) + " " + str(groupName)) res = False break else: self.printERROR(_("User %s is not a member of any group")%\ str(userName)) res = False break if not res: return False for userName in users: userSearch = self.searchUserToNameOrId(userName) uid = userSearch[0][0][1]['uid'][0] modAttrs = [(ldap.MOD_DELETE, 'departmentNumber', None)] userDN = self.addDN("uid="+uid, self.relUsersDN) res = self.modAttrsDN(userDN, modAttrs) if not res: break return res def renameGroup(self, oldName, newName): """Изменяет имя группы""" searchOldGroup = self.searchGroupToName(oldName) if not searchOldGroup: self.printERROR(\ _("Old group name %s not found in Jabber service")%str(oldName)) return False searchNewGroup = self.searchGroupToName(newName) if searchNewGroup: self.printERROR(\ _("New group name %s found in Jabber service")%str(newName)) return False groupDN = self.addDN("cn="+oldName, self.relGroupsDN) searchUsers = self.searchUsersToGroup(oldName) if searchUsers: flagError = False for data in searchUsers: uid = data[0][1]['uid'][0] userDN = self.addDN("uid="+uid, self.relUsersDN) modAttrs = [(ldap.MOD_REPLACE, 'departmentNumber', newName)] res = self.modAttrsDN(userDN, modAttrs) if not res: flagError = True break if flagError: return False newFirstDn = "cn=" + newName oldDN = groupDN res = self.modifyElemDN(oldDN, newFirstDn) return res def modUserJabberPasswd(self, userName, options): """Устанавливает пароль Jabber пользователя и меняет его опции""" # Проверим установлен ли сервис jabber if not self.initialChecks("jabber"): return False resSearch = self.searchUserToNameOrId(userName) if not resSearch: self.printERROR( _("User %s is not found in Jabber service") % str(userName)) return False # Изменяемые аттрибуты пользователя modAttrs = [] # Включаем пользователя if options.has_key('u'): modAttrs += [(ldap.MOD_REPLACE, 'initials', "Yes")] # Выключаем пользователя elif options.has_key('l'): modAttrs += [(ldap.MOD_REPLACE, 'initials', "No")] if not options: optPasswd = {"p":""} userPwd = self.getUserPassword(optPasswd, "p", False) if userPwd == False: return False userPwdHash = userPwd if resSearch[0][0][1].has_key('userPassword'): modAttrs.append((ldap.MOD_REPLACE, 'userPassword', userPwdHash)) else: modAttrs.append((ldap.MOD_ADD, 'userPassword', userPwdHash)) if modAttrs: uid = resSearch[0][0][1]['uid'][0] DN = self.addDN("uid="+userName, self.relUsersDN) if not self.modAttrsDN(DN, modAttrs): return False if options.has_key('l'): self.printSUCCESS(_("Locked Jabber user %s")% str(userName)) if options.has_key('u'): self.printSUCCESS(_("Unlocked Jabber user %s")%\ str(userName)) if not options: self.printSUCCESS(_("Changed Jabber user password")) return True return False def modUserJabberServer(self, userName, options, printSuccess=True): """Модифицирует настройки пользователя Jabber в LDAP""" # Проверим установлен ли сервис jabber if not self.initialChecks("jabber"): return False res = self.searchUserToNameOrId(userName) if not res: self.printERROR(_("User %s is not found in Jabber service")%\ str(userName)) return False # Изменяемые аттрибуты пользователя modAttrs = [] # Изменяем Jabber ID jabber_hosts = self.get_jabber_hosts() if options.has_key('j'): # Изменяем JID jabberId = options['j'] if not "@" in jabberId: jabberId = "%s@%s" %(jabberId,self.clVars.Get("sr_jabber_host")) else: if len(jabberId.split("@")) != 2: self.printERROR(_("JID %s incorrect") %jabberId) return False if jabberId.rpartition('@')[2] not in jabber_hosts: self.printERROR( _("JID %s not supported on this jabber hosts") %jabberId) return False searchUser = self.searchUserToId(jabberId) if searchUser: foundUserName = searchUser[0][0][1]['uid'][0] if foundUserName != userName: self.printERROR(_("User %s") %str(foundUserName) + " " +\ _("has a JID %s") %jabberId) return False # добавляем jabberID в Unix if self.isServiceSetup("unix",False): if not self.servUnixObj.setUserJabberID(userName, jabberId): self.printERROR(_("Failed set jabberID for user %s \ in Unix service") %str(jabberId)) return False if res[0][0][1].has_key('mail'): modAttrs.append((ldap.MOD_REPLACE, 'mail', jabberId)) else: modAttrs.append((ldap.MOD_ADD, 'mail', jabberId)) modAttrs.append((ldap.MOD_REPLACE,'cn',jabberId.partition("@")[0])) # Изменяет группу в которую входит пользователь if options.has_key('g'): userGroup = options['g'] if self.setUserGroup(userName, userGroup, res): self.printSUCCESS(_("Replaced user group")) else: self.printERROR(_("Not replaced user group")) return False #загружаем картинку if options.has_key('i'): photoFile = options['i'] if not self.setJpegPhotoUser(userName, photoFile): self.printERROR(_("Can not add jpeg photo for user") + " " +\ str(userName)) return False # Включаем пользователя if options.has_key('U'): modAttrs += [(ldap.MOD_REPLACE, 'initials', "Yes")] # Выключаем пользователя elif options.has_key('L'): modAttrs += [(ldap.MOD_REPLACE, 'initials', "No")] # Изменяем комментарий к пользователю if options.has_key('c'): comment = options['c'] modAttrs += [(ldap.MOD_REPLACE, 'sn', comment)] # Изменяем пароль пользователя userPwd = self.getUserPassword(options, "p", "P") if userPwd == False: return False if userPwd: userPwdHash = userPwd if res[0][0][1].has_key('userPassword'): modAttrs.append((ldap.MOD_REPLACE, 'userPassword', userPwdHash)) else: modAttrs.append((ldap.MOD_ADD, 'userPassword', userPwdHash)) if modAttrs: uid = res[0][0][1]['uid'][0] DN = self.addDN("uid="+uid, self.relUsersDN) if not self.modAttrsDN(DN, modAttrs): return False if printSuccess: if options.has_key('c'): self.printSUCCESS(_("Modified comment (full name)")) if options.has_key('L'): self.printSUCCESS(_("Locked Jabber user %s")%str(userName)) if options.has_key('U'): self.printSUCCESS(_("Unlocked Jabber user %s")\ %str(userName)) if options.has_key('P') or options.has_key('p'): self.printSUCCESS(_("Modified Jabber user password")) if options.has_key('j'): self.printSUCCESS(_("JID changed, a new JID is %s")\ %jabberId) if printSuccess and options.has_key('i'): self.printSUCCESS(_("Set image %s for Jabber user")%\ str(options['i']) + " " + str(userName)) return True def modGroupJabberServer(self, groupName, options): """Модифицирует настройки группы пользователей Jabber""" # Проверим установлен ли сервис jabber if not self.initialChecks("jabber"): return False searchGroup = self.searchGroupToName(groupName) if not searchGroup: self.printERROR(_("Group name %s is not found in Jabber service")\ %str(groupName)) return False # Добавляем список пользователей в группу if options.has_key('a'): # добавляемые пользователи в группу users = options['a'].split(',') res = self.addUsersGroupJabber(users, groupName) if res: self.printSUCCESS(_("Appended list users to group") + " " +\ str(groupName)) else: self.printERROR(_("Can not append list users to group") +\ " " + str(groupName)) return False # Удаляем список пользователей из группы if options.has_key('d'): # удаляемые пользователи из группы users = options['d'].split(',') res = self.delUsersGroupJabber(users, groupName) if res: self.printSUCCESS(_("Deleted list users from group") + " " +\ str(groupName)) else: self.printERROR(_("Can not delete list users from group") +\ " " + str(groupName)) return False # Изменяем комментарий к группе if options.has_key('c'): gecos = options['c'] modAttrs = [(ldap.MOD_REPLACE, 'description', gecos)] groupDN = self.addDN("cn="+groupName, self.relGroupsDN) if self.modAttrsDN(groupDN, modAttrs): self.printSUCCESS(_("Modified group comment")) else: self.printERROR(_("Can not modify comment group") +\ " " + str(groupName)) return False # Изменяем имя группы if options.has_key('n'): newGroupName = options['n'] oldGroupName = searchGroup[0][0][1]["cn"][0] if self.renameGroup(oldGroupName, newGroupName): self.printSUCCESS(_("Group renamed to %s")\ %newGroupName) else: self.printERROR(_("Can not rename group") +\ " " + str(groupName)) return False return True def delUserJabberServer(self, userName, options, printSuccess=True): """Удаляем Jabber пользователя""" # Проверим установлен ли сервис jabber if not self.initialChecks("jabber"): return False # Ищем Jabber пользователя resSearch = self.searchUserToNameOrId(userName) if not resSearch: self.printERROR (_("ERROR") + ": " +\ _("User %s is not found in Jabber service") % str(userName)) return False uid = resSearch[0][0][1]['uid'][0] # Удаляем jabberID из Unix сервиса # удаляем jabberID из Unix if self.isServiceSetup("unix",False) and\ self.servUnixObj.searchUnixUser(uid): if not self.servUnixObj.deleteUserJabberID(uid): return False # Удаляем пользователя delDN = self.addDN("uid=" + uid, self.relUsersDN) if not self.delDN(delDN): self.printERROR(_("Jabber user %s is not deleted")%userName) return False if printSuccess: self.printSUCCESS(_("Jabber user %s is deleted")%userName) return True def delGroupJabberServer(self, groupName, options): """Удаляет группу пользователей Jabber""" # Проверим установлен ли сервис jabber if not self.initialChecks("jabber"): return False res = self.searchGroupToName(groupName) if not res: self.printERROR( _("Group %s is not found in Jabber service")%groupName) return False users = [] flagError = False searchUsers = self.searchUsersToGroup(groupName) if searchUsers: for data in searchUsers: users.append(data[0][1]['uid'][0]) if not self.delUsersGroupJabber(users, groupName): flagError = True if not flagError: delDN = self.addDN("cn="+groupName, self.relGroupsDN) res = self.delDN(delDN) if not res: flagError = True if flagError: self.printERROR(_("Can not delete Jabber group") +\ " " + groupName) return False else: self.printSUCCESS( _("Jabber group %s is deleted")%groupName) return True @adminConnectLdap def addGroupJabberServer(self, groupName, options): """Добавляет группу пользователей Jabber""" # Проверим установлен ли сервис jabber if not self.initialChecks("jabber"): return False # Если группа существует выходим без ошибки if self.searchGroupToName(groupName): self.printERROR(\ _("group name %s is found in Jabber service") %\ str(groupName)) return False self.clVars.Set("ur_group",groupName) # Комментарий к группе groupGecos = self.servUnixObj.groupGecos if options.has_key('c'): groupGecos = options['c'] self.clVars.Set("ur_group_comment",groupGecos) ldifFile = self.ldifFileGroup groupLdif = self.createLdif(ldifFile) if not groupLdif: print self.getError() return False if not self.ldapObj.getError(): self.ldapObj.ldapAdd(groupLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False self.printSUCCESS(_("Added group '%s' in Jabber service")\ %groupName) return True def upgradeService(self): """Обновляет настройки и базу данных Используется при установке сервиса и его апдейте """ # Флаг ошибки searchUsers = self.searchAllUsers() flagError = False for fieldUser in searchUsers: if fieldUser[0][1].has_key("mail"): userName = fieldUser[0][1]['uid'][0] jabberId = fieldUser[0][1]['mail'][0] cn = fieldUser[0][1]['cn'][0] if cn != jabberId.partition("@")[0]: options = {"j":jabberId} # Изменяем аттрибут cn у всех пользователей if not self.modUserJabberServer(userName, options, False): self.printERROR(_("Failed set jabberID for user %s \ in Jabber service") %str(jabberId)) flagError = True break # Изменяем jabberId у всех пользователей сервиса Unix if not self.servUnixObj.setUserJabberID(userName, jabberId): self.printERROR(_("Failed set jabberID for user %s \ in Unix service") %str(jabberId)) flagError = True break if flagError: return False return True def get_jabber_hosts(self): jabber_host = self.clVars.Get('sr_jabber_host') jabber_hosts = self.clVars.Get('sr_jabber_hosts').split(',') jabber_hosts.append(jabber_host) return list(set(jabber_hosts)) @adminConnectLdap def addUserJabberServer(self, userName, options, checkSetup=True): """Добавляет jabber пользователя""" jabber_hosts = self.get_jabber_hosts() # Проверим установлен ли сервис jabber if checkSetup and not self.initialChecks("jabber"): return False #jabber id jabberId = "%s@%s" %(userName,self.clVars.Get("sr_jabber_host")) if options.has_key('j'): # Изменяем JID jabberId = options['j'] if not "@" in jabberId: jabberId = "%s@%s" %(jabberId,self.clVars.Get("sr_jabber_host")) else: if len(jabberId.split("@")) != 2: self.printERROR(_("JID %s incorrect") %jabberId) return False if jabberId.rpartition('@')[2] not in jabber_hosts: self.printERROR( _("JID %s not supported on this jabber hosts") %jabberId) return False # добавляем jabberID в Unix if self.isServiceSetup("unix",False): if not self.servUnixObj.setUserJabberID(userName, jabberId): self.printERROR(_("Failed set jabberID for user %s \ in Unix service") %str(jabberId)) return False self.clVars.Set("sr_jabber_user_id", jabberId) if self.searchUserToName(userName): self.printERROR(_("User %s exists in Jabber service") %userName) return False if self.searchUserToId(jabberId): self.printERROR(_("JID %s exists in Jabber service") %jabberId) return False # Пароль пользователя Jabber userPwd = self.getUserPassword(options, "p", "P") if userPwd == False: return False if not userPwd: userPwd = "crypt{xxx}" self.clVars.Set("ur_hash",userPwd) self.clVars.Set("ur_name", userName) #Полное имя пользователя fullNameUser = self.servUnixObj.fullNameUser if options.has_key('c'): fullNameUser = options['c'] else: # Проверяем установку сервиса не печатая ошибку в случае # если сервис не установлен if self.isServiceSetup("unix",False): resUnix = self.servUnixObj.searchUnixUser(userName) # Берем комментарий для пользователя из Unix if resUnix and resUnix[0][0][1].has_key('cn'): fullNameUser = resUnix[0][0][1]['cn'][0] self.clVars.Set("ur_fio",fullNameUser) ldifFile = self.ldifFileUser userLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): #Добавляем пользователя в LDAP self.ldapObj.ldapAdd(userLdif) #ldapObj.ldapAdd(userLdif1) # не переделывать на else if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False # загружаем картинку if options.has_key('i'): photoFile = options['i'] if not self.setJpegPhotoUser(userName, photoFile): self.printERROR(_("Can not add jpeg photo for user") + " " +\ str(userName)) self.delUserJabberServer(userName, options, False) return False self.printSUCCESS(_("Added user in Jabber service")) return True def setupJabberServer(self, options): """Начальная настройка Jabber сервиса""" # Принудительная установка forceOptions = False if options.has_key("f"): forceOptions = True # Создаем объект переменных и начальная проверка if not self.initialChecksSetup(): return False #self.clVars.printVars() #return True if self.clVars.Get("sr_ldap_set") != "on": self.printERROR(_("LDAP service is not setuped")) self.printWARNING(_("Setup LDAP service")) self.printWARNING(" cl-setup ldap") return False # В случае если сервер установлен if self.clVars.Get("sr_jabber_set") == "on" and\ not forceOptions: self.printWARNING (_("WARNING") + ": " +\ _("Jabber server is configured")+ ".") return True if not forceOptions: # предупреждение при выполнении этой программы будут изменены # конфигурационные файлы сервиса Mail (программы Postfix и Dovecot) self.printWARNING (_("WARNING") + ": " + _("Executing of the program will change") + " " + _("the configuration files of Jabber service") +" ("+ _("program Ejabberd") + ")." ) # если вы готовы продолжить работу программы нажмите Y если нет n messDialog = \ _("If you are ready to continue executing the program") + ", "+\ _("input 'yes'") +", "+ _("if not 'no'") if not self.dialogYesNo(messDialog): return True else: # делаем backup # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False bakupObj = servLdap() if not bakupObj.backupServer(): return False # Удаляем переменные сервиса в ini файлах self.deleteServiceVarsInFile("jabber") # Cоздаем объект переменные self.createClVars() # Удаляем из автозапуска демона if not self.delDaemonAutostart("ejabberd"): return False # останавливаем сервис Jabber if not self.stopServices(["jabber"]): return False # Имя устанавливаемого сервиса self.clVars.Set("cl_pass_service","jabber") self.clVars.Write("sr_jabber_set","off") # Jabber host fullHostName = "%s.%s"%(self.clVars.Get('os_net_hostname'), self.clVars.Get('os_net_domain')) jabberHosts = fullHostName if options.has_key("host"): fullHostName = options['host'] if not "." in fullHostName: fullHostName = "%s.%s" %(fullHostName, self.clVars.Get('os_net_domain')) self.clVars.Set("sr_jabber_host",fullHostName,True) # Устанавливаем дополнительные хосты jabber cервиса if options.has_key("hosts"): hosts = options['hosts'].split(",") jabberHostsList = [self.clVars.Get("sr_jabber_host")] for host in hosts: apHost = host if not "." in host: apHost = "%s.%s" %(host, self.clVars.Get('os_net_domain')) jabberHostsList.append(apHost) unicHostsList = [] for host in jabberHostsList: if not host in unicHostsList: unicHostsList.append(host) jabberHosts = ",".join(unicHostsList) self.clVars.Set("sr_jabber_hosts",jabberHosts,True) # Cоздаем объект профиль устанавливая директорию jabber для # файлов профилей if not self.applyProfilesFromService('jabber'): return False # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False else: if not self.restartLdapServer(): return False # Подключаемся к LDAP cерверу if not shareLdap.getLdapObjInFile(self): return False # Находим в LDAP Jabber сервис resSearch = self.searchService() ret = True if resSearch: delDN = self.relDN ret = self.deleteDN(delDN) if ret: self.printOK(_("Remove Jabber DN from LDAP Database") + " ...") else: self.printERROR(\ _("Can not remove Jabber DN from LDAP Database")) if not ret: return False ldifFile = self.ldifFileBase baseLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): self.ldapObj.ldapAdd(baseLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False # Администратор сервиса adminName = "admin" adminFullName = "%s@%s" %(adminName, self.clVars.Get("sr_jabber_host")) print _("Enter the %s password") %adminFullName if not self.addUserJabberServer(adminName,{'p':""}, False): return False # Записываем данные администратора сервиса Jabber ldapParser = iniLdapParser() ldapParser.setVar("jabber", {"DN":self.clVars.Get("ld_jabber_dn"), "PASS":self.clVars.Get("ld_jabber_pw")}) self.printOK(_("Added ldif file") + " ...") # создаем сертификат если есть используем прежний if not self.createJabberCertificate(): return False if not os.path.exists("/etc/jabber/ssl.pem"): self.printERROR(_("Can not create Jabber certificate")) return False textLines = self.execProg("/etc/init.d/ejabberd start", False, False) if textLines == False: self.printNotOK(_("Starting") + " " + "Ejabberd" + " ...") return False else: self.printOK(_("Starting") + " " + "Ejabberd" + " ...") # Устанавливаем автозапуск демона if not self.setDaemonAutostart("ejabberd"): return False #запишем переменные для сервера jabberHost = self.clVars.Get("sr_jabber_host") self.clVars.Write("sr_jabber_host",jabberHost,True,"local") self.clVars.Write("sr_jabber_hosts", self.clVars.Get("sr_jabber_hosts"), True,"local") self.clVars.Write("sr_jabber_history", self.clVars.Get("sr_jabber_history"), True,"local") #запишем переменные для клиента clientVars = ["sr_jabber_host","sr_jabber_crypt","sr_jabber_port"] if not self.saveVarsClient(clientVars): return False self.clVars.Write("sr_jabber_set","on") self.printOK(_("Jabber service configured") + " ...") return True class servSamba(shareLdap): """Методы севисa Samba""" relGrDN = 'ou=Groups' relUsDN = 'ou=Users' relCsDN = 'ou=Computers' relServDN = 'ou=Samba' # Используемые ldif файлы ldifFileBase = "/usr/lib/calculate/calculate-server/ldif/samba_base.ldif" ldifFileGroup = "/usr/lib/calculate/calculate-server/ldif/samba_group.ldif" # Файл для определения к какому из серверов # подключился клиент в случае включения репликации shareReplFile = ".reprun" def __init__(self, unixObj=False): shareLdap.__init__(self) self.relDN = self.addDN(self.relServDN,self.ServicesDN) # DN пользователей, относительно базового DN self.relUsersDN = self.addDN(self.relUsDN, self.relDN) # DN групп пользователей, относительно базового DN self.relGroupsDN = self.addDN(self.relGrDN, self.relDN) # DN, компьютеров относительно базового DN self.relComputersDN = self.addDN(self.relCsDN, self.relDN) if unixObj: # получаем объект сервиса Unix self.servUnixObj = unixObj else: # создаем объект сервиса Unix self.servUnixObj = servUnix(self) def addStaticGroups(self): """Добавляет статические группы Если группы нет она будет добавлена в противном случае пропущена """ # Находим группы у которых есть аттрибут type groupsSambaList = filter(lambda x: x[1].type, self.staticGroups.items()) groupsSamba = {} groupsSamba.update(groupsSambaList) flagError = False for grObj in groupsSamba.values(): opt = {} opt['c'] = grObj.comment opt['t'] = grObj.type if grObj.sid: opt['s'] = grObj.sid else: opt['r'] = grObj.rid opt['g'] = grObj.gid groupName = grObj.name if not self.searchSambaGroupName(groupName) and\ not self.addGroupSambaServer(groupName, opt, False, False): flagError = True break if flagError: return False return True def getMaxGidSamba(self): """Находит максимальный добавленный gid в Unix""" return self.getMaxAttrDN(self.relGroupsDN, "*", "cn", self.servUnixObj.minGid, self.servUnixObj.maxGid, "gidNumber") def delReplFile(self, clVars): """Удаляем файл из директории share в случае отключения репликации""" # Файл для определения к какому из серверов # подключился клиент fileReplRun = os.path.join(clVars.Get("sr_samba_share_path"), self.shareReplFile) if os.path.exists(fileReplRun): try: os.remove(fileReplRun) except: self.printERROR(_("Can not remove %s")%fileReplRun) return False return True def addReplFile(self, clVars): """Добавляем файл в директорию share в случае влючения репликации""" fileReplRun = os.path.join(clVars.Get("sr_samba_share_path"), self.shareReplFile) if not os.path.exists(fileReplRun): # Создаем файл # Текст внутри файла warning = _("The file was added by the calculate-server.") + "\n" warning += _("If all clients of this server are calculate-client \ of version > 2.1.10, then you can delete this file.") + "\n" if not self.createUserFile(fileReplRun,warning,0,0, mode=0644): return False return True def getLdapObjInFile(self): """Cоединение с LDAP администратором Samba сервиса""" return shareLdap.getLdapObjInFile(self, "samba") def delUsersGroupSamba(self, users, groupName): """Удаление пользователей из списка из группы Samba""" def getPrimaryUsers(): gidNumber = res[0][0][1]["gidNumber"][0] searchUsers = self.servUnixObj.searchUnixUserPrimGroup(gidNumber) foundUserNames = [] if searchUsers: for data in searchUsers: foundUserNames.append(data[0][1]["uid"][0]) if foundUserNames: primaryUsers = list(set(foundUserNames)&set(users)) if primaryUsers: self.printERROR(_("%s is primary group")% groupName + " " +\ _("for users (%s)")%", ".join(primaryUsers)) return False return True res = self.searchSambaGroupName(groupName) if not res : self.printERROR(_("group name is not found in Samba service")) return False if not res[0][0][1].has_key("memberUid"): if not getPrimaryUsers(): return False self.printERROR( _("Member list of group %s is empty")%str(groupName)) return False memberUsers = res[0][0][1]["memberUid"] flagError =False for user in users: if not user in memberUsers: flagError = True break if flagError: if not getPrimaryUsers(): return False self.printERROR( _("User %s is not found in group")%str(user)+" "+\ str(groupName)) return False modAttrs = [] for userName in users: modAttrs.append((ldap.MOD_DELETE, 'memberUid', userName)) groupDN = self.addDN("cn="+groupName, self.relGroupsDN) return self.modAttrsDN(groupDN, modAttrs) def delUserInGroup(self, userName): """Удаление из групп в которые входит пользователь""" userInGroups = self.searchSambaMemberGid(userName) modAttrs = [(ldap.MOD_DELETE, 'memberUid', userName)] flagError = False for group in userInGroups: groupName = group[0][1]['cn'][0] groupDN = self.addDN("cn=" + groupName, self.relGroupsDN) if not self.modAttrsDN(groupDN, modAttrs): flagError = True break if flagError: return False else: return True def delGroupSambaServer(self, groupName, options, printSuccess=True, checkPrimaryGroup=True): """Удаляет группу пользователей Samba""" # Проверим установлен ли сервис Samba if not self.initialChecks("samba"): return False res = self.searchSambaGroupName(groupName) if not res: self.printERROR( _("Group %s is not found in Samba service")%groupName) return False if checkPrimaryGroup: groupId = res[0][0][1]['gidNumber'][0] if self.servUnixObj.searchUnixUserPrimGroup(groupId): self.printWARNING(_("cannot remove user's primary group") + ".") return True delDN = self.addDN("cn="+groupName, self.relGroupsDN) res = self.delDN(delDN) if res: if printSuccess: self.printSUCCESS( _("Group %s is deleted")%groupName) return True else: self.printERROR(_("Can not delete group") + " " + groupName) return False def delUserSambaServer(self,userName,options,printSuccess=True, backup=True, notDeletedDirs=[]): """Удаляем Samba пользователя""" # Проверим установлен ли сервис samba if not self.initialChecks("samba"): return False if "$" in userName: # удаляемая машина delUser = userName.replace('$','') + "$" if not self.searchSambaMachine(delUser): self.printERROR (_("ERROR") + ": " +\ _("Samba machine %s is not found in Samba service")%\ str(delUser)) return False else: # удаляемый пользователь delUser = userName if not self.searchSambaUser(delUser): self.printERROR (_("ERROR") + ": " +\ _("Samba user %s is not found in Samba service") %\ str(delUser)) return False winProfDir =\ os.path.join(self.clVars.Get("sr_samba_winprof_path"), userName) win7ProfDir =\ os.path.join(self.clVars.Get("sr_samba_winprof_path"), userName+".V2") linProfDir =\ os.path.join(self.clVars.Get("sr_samba_linprof_path"), userName) userHomeDir =\ os.path.join(self.clVars.Get("sr_samba_home_path"), userName) userNetlogonDir =\ os.path.join(self.clVars.Get("sr_samba_winlogon_path"), userName) if options.has_key('r'): backup = False # Делаем сохранение данных удаляемого пользователя if backup: if os.path.exists(winProfDir) and os.listdir(winProfDir): if not self.backupDelUser(userName, 'samba/winprofile', winProfDir): return False if os.path.exists(win7ProfDir) and os.listdir(win7ProfDir): if not self.backupDelUser(userName, 'samba/win7profile', win7ProfDir): return False if os.path.exists(linProfDir) and os.listdir(linProfDir): if not self.backupDelUser(userName, 'samba/linprofile', linProfDir): return False if os.path.exists(userHomeDir)and os.listdir(userHomeDir): if not self.backupDelUser(userName, 'samba/home', userHomeDir): return False if os.path.exists(userNetlogonDir) and os.listdir(userNetlogonDir): if not self.backupDelUser(userName, 'samba/netlogon', userNetlogonDir): return False textLine = self.execProg("smbpasswd -x %s" %(delUser)) flagError = False if textLine == False: flagError = True # Удаляем пользователя из Samba групп if not flagError: if not self.delUserInGroup(userName): flagError = True if flagError: self.printERROR(_("ERROR") + ": " +\ _("Can not delete Samba user") + " " + str(delUser)) return False else: # Удаляем win7 профиль if not win7ProfDir in notDeletedDirs and\ os.path.exists(win7ProfDir): self.removeDir(win7ProfDir) # Удаляем win профиль if not winProfDir in notDeletedDirs and\ os.path.exists(winProfDir): self.removeDir(winProfDir) # Удаляем lin профиль if not linProfDir in notDeletedDirs and\ os.path.exists(linProfDir): self.removeDir(linProfDir) # Удаляем домашнюю директорию if not userHomeDir in notDeletedDirs and\ os.path.exists(userHomeDir): self.removeDir(userHomeDir) # Удаляем netlogon if not userNetlogonDir in notDeletedDirs and\ os.path.exists(userNetlogonDir): self.removeDir(userNetlogonDir) if self.servUnixObj.searchUnixUser(userName) and\ not self.servUnixObj.modUserUnixServer(userName,{"I":""},False): return False if printSuccess: self.printSUCCESS(_("Deleted Samba user %s") % str(delUser)) return True @adminConnectLdap def addUserSambaServer(self,userName,options,pwDialog=False, checkSetup=True,pwd=False): """Добавляет LDAP пользователя в LDAP-сервер""" # Проверим установлен ли сервис samba if checkSetup and not self.initialChecks("samba"): return False # Добавление машины samba if options.has_key('w'): if self.addMachineSambaServer(userName, options): return True else: return False # id пользователя Unix uidUnixUser = False resSearch = self.servUnixObj.searchUnixUser(userName) if resSearch: uidUnixUser = resSearch[0][0][1]['uidNumber'][0] ## создание пользователя Unix опция f #if not resSearch and not options.has_key('f'): #self.printERROR( #_("User %s is not found in Unix service")%\ #str(userName)) #return False if self.searchSambaUser(userName): self.printERROR(_("Samba user exists")) return False #пароль пользователя userPwd = "" if pwd: userPwd = pwd else: #диалог ввода пароля if not pwDialog: pwDialog = [_("New SMB password"), _("Retype new SMB password")] userPwd = self.getUserPassword(options, "p", "P", pwDialog) if userPwd == False: return False flagCreateUnixUser = False if not resSearch: # Добавим пользователя LDAP optUnix = {} # id пользователя if options.has_key('u'): optUnix['u'] = options['u'] # Группа пользователя if options.has_key('g'): optUnix['g'] = options['g'] # Группы в которые входит пользователь if options.has_key('G'): optUnix['G'] = options['G'] # Полное имя пользователя if options.has_key('c'): optUnix['c'] = options['c'] # shell if options.has_key('s'): optUnix['s'] = options['s'] # Домашняя директория if options.has_key('d'): optUnix['d'] = options['d'] # Cделаем пользователя видимым if optUnix.has_key('u'): try: int(optUnix['u']) except: self.printERROR(_("UID is not number")) return False if int(optUnix['u']) >= 1000: optUnix['v'] = "" else: optUnix['v'] = "" if not self.servUnixObj.addUserUnixServer(userName, optUnix, False,userPwd,True): self.printERROR (_("Can not add user")+ " " +\ str(userName) + _(" in Unix service")) return False flagCreateUnixUser = True else: if userPwd: # Меняем пароль у пользователя Unix if not self.servUnixObj.modUserUnixPasswd(userName,{},userPwd): return False # Делаем пользователя Unix видимым if uidUnixUser==False or int(uidUnixUser) >=1000: if not self.servUnixObj.modUserUnixServer(userName, {"V":""},False): return False if userPwd: textLine = self.execProg("smbpasswd -a -s %s" %(userName), "%s\n%s\n" %(userPwd,userPwd)) else: textLine = self.execProg("smbpasswd -a -n %s" %(userName)) if textLine != False: flagError = False if options.has_key('G'): # Изменяем Samba группы пользователя userGroups = options['G'].split(',') data = self.searchUnixAndSambaGroups(userGroups, True) if data and type(data) == types.TupleType: userGroupNamesUnix, userGroupNamesSamba = data else: flagError = True # Удаляем Samba группы у пользователя if not flagError and not self.delUserInGroup(userName): flagError = True if not flagError: for group in userGroupNamesSamba: if not self.addUsersGroupSamba([userName], group): flagError = True break if not flagError: winProfDir =\ os.path.join(self.clVars.Get("sr_samba_winprof_path"), userName) win7ProfDir =\ os.path.join(self.clVars.Get("sr_samba_winprof_path"), userName+".V2") linProfDir =\ os.path.join(self.clVars.Get("sr_samba_linprof_path"), userName) userHomeDir =\ os.path.join(self.clVars.Get("sr_samba_home_path"), userName) userNetlogonDir =\ os.path.join(self.clVars.Get("sr_samba_winlogon_path"), userName) message = _("Do you want to restore deleted user %s data?")\ %userName + "\n" + "'yes', 'no'" resWinProf = self.restorePathDelUser(userName, winProfDir, "samba/winprofile", message) removeProfileBack = False if not resWinProf: flagError = True createDirWinProfile = False else: term, createDirWinProfile, removeProfileBack = resWinProf resWin7Prof = self.restorePathDelUser(userName, win7ProfDir, "samba/win7profile", term) removeProfile7Back = False if not resWin7Prof: flagError = True createDirWin7Profile = False else: term, createDirWin7Profile, removeProfile7Back = resWin7Prof removeHomeBack = False if not flagError: resHome = self.restorePathDelUser(userName, userHomeDir, "samba/home", term) if not resHome: flagError = True createDirHome = False else: term, createDirHome, removeHomeBack = resHome removeLogonBack = False if not flagError: resLogon = self.restorePathDelUser(userName, userNetlogonDir, "samba/netlogon", term) if not resLogon: flagError = True createDirLogon = False else: term, createDirLogon, removeLogonBack = resLogon removeLinProfileBack = False if not flagError: resLinProf = self.restorePathDelUser(userName, linProfDir, "samba/linprofile", term) if not resLinProf: flagError = True createDirLinProfile = False else: term,createDirLinProfile,removeLinProfileBack = resLinProf # Cоздадим нужные директории if not flagError: resSearchUnix = self.servUnixObj.searchUnixUser(userName) resPasswd = False if resSearchUnix: uid = int(resSearchUnix[0][0][1]['uidNumber'][0]) gid = int(resSearchUnix[0][0][1]['gidNumber'][0]) else: resPasswd = self.servUnixObj.searchPasswdUser(userName) if resPasswd: uid = int(resPasswd.split(":")[2]) gid = int(resPasswd.split(":")[3]) # Не удаляемые директории notDeletedDirs = filter(lambda x:x and os.path.exists(x), (createDirHome,createDirLogon, createDirWin7Profile, createDirWinProfile,createDirLinProfile)) if (resPasswd or resSearchUnix) and\ (options.has_key('n') or int(uid) >=1000): # Cоздаем домашнюю директорию if createDirHome: if not self.createUserDir(uid, gid, createDirHome): flagError = True # Cоздаем иконку в домашней директории if not flagError: fileTxt = "[Desktop Entry]\nIcon=user-home" fileDirectory = os.path.join(createDirHome, ".directory") if not self.createUserFile(fileDirectory, fileTxt, uid, gid): flagError = True # Cоздаем директорию netlogon if not flagError and createDirLogon: if not self.createUserDir(uid, gid, createDirLogon): flagError = True # cоздадим cmd файл для монтирования ресурсов в windows if not flagError: netbios = self.clVars.Get("sr_samba_netbios") netbios = netbios.upper() fileTxt='NET USE R: /D\r\nNET USE R: \\\\%s\\share\ \r\nNET USE T: /D\r\nNET VIEW \\\\%s | find "ftp"\r\n\ if %%errorlevel%%==0 NET USE T: \\\\%s\\ftp' %(netbios,netbios,netbios) fileDirectory = os.path.join(createDirLogon, "start.cmd") if not self.createUserFile(fileDirectory, fileTxt, uid, gid): flagError = True # Cоздаем директорию профиля win if not flagError and createDirWinProfile: if not self.createUserDir(uid,gid,createDirWinProfile): flagError = True # Cоздаем директорию профиля win7 if not flagError and createDirWin7Profile: if not self.createUserDir(uid,gid,createDirWin7Profile): flagError = True # Создаем директорию профиля lin if not flagError and createDirLinProfile: if not self.createUserDir(uid,gid,createDirLinProfile): flagError = True if not flagError: # Удаляем директорию бекапа профиля win7 if removeProfile7Back and\ os.path.exists(removeProfile7Back): self.removeDir(removeProfile7Back) self.removeEmptyDir(os.path.split(removeProfile7Back)[0]) # Удаляем директорию бекапа профиля win if removeProfileBack and\ os.path.exists(removeProfileBack): self.removeDir(removeProfileBack) self.removeEmptyDir(os.path.split(removeProfileBack)[0]) # Удаляем директорию бекапа профиля lin if removeLinProfileBack and\ os.path.exists(removeLinProfileBack): self.removeDir(removeLinProfileBack) self.removeEmptyDir(os.path.split(removeLinProfileBack)[0]) # Удаляем бекап домашней директории if removeHomeBack and\ os.path.exists(removeHomeBack): self.removeDir(removeHomeBack) self.removeEmptyDir(os.path.split(removeHomeBack)[0]) # Удалим директорию logon пользователя if removeLogonBack and\ os.path.exists(removeLogonBack): self.removeDir(removeLogonBack) self.removeEmptyDir(os.path.split(removeLogonBack)[0]) if flagError: self.delUserSambaServer(userName,{},False,False,notDeletedDirs) if flagCreateUnixUser: self.servUnixObj.delUserUnixServer(userName, {}, False, False) self.printERROR(_("Can not add user %s")%userName) return False if flagCreateUnixUser: self.printSUCCESS(_("Added user %s in Unix service")%userName) self.printSUCCESS(_("Added user %s in Samba service")%userName) return True else: if flagCreateUnixUser: self.servUnixObj.delUserUnixServer(userName, {}, False, False) self.printERROR(_("Can not add user %s")%userName) return False def searchSambaUser(self, userName): """Находит пользователя сервиса Samba""" resSearch = self.searchLdapDN(userName, self.relUsersDN, "uid") return resSearch def searchSambaMachine(self, machineName): """Находит машину (компьютер) сервиса Samba""" resSearch = self.searchLdapDN(machineName, self.relComputersDN, "uid") return resSearch def searchAllSambaMachines(self): """Находит все машины (компьютеры) сервиса Samba""" resSearch = self.searchLdapDN("*", self.relComputersDN, "uid") return resSearch def searchSambaMemberGid(self, userName): """Ищет группы сервиса Samba в котрых есть данный пользователь""" resSearch = self.searchLdapDN(userName, self.relGroupsDN, "memberUid") return resSearch def searchUsersInGroupSamba(self, usersNames, groupName): """Ищет спиcок пользователей в группе, ищет в Samba В случае успеха выводит список найденных пользователей если нет группы False если ничего не найдено пустой список """ res = self.searchSambaGroupName(groupName) if not res: return False else: findUsers = [] if res[0][0][1].has_key('memberUid'): usersInGroup = res[0][0][1]['memberUid'] for userName in usersNames: if userName in usersInGroup: findUsers.append(userName) return findUsers def searchUnixAndSambaGroups(self, userGroups, checkSetup=True): """Ищет Samba и Unix группы из списка userGroups""" # Ищем группы в Unix сервисе rezultUnix, groupNamesUnix, errMessUnix =\ self.servUnixObj.searchGroupsUnix(userGroups, False) grUnix = groupNamesUnix groupNamesUnix = groupNamesUnix.keys() # Если установлен сервис Samba groupNamesSamba = [] gidNotFound = [] if checkSetup and self.isServiceSetup("samba", False): rezultSamba, groupNamesSamba, errMessSamba =\ self.searchGroupsSamba(userGroups, False) grSamba = groupNamesSamba groupNamesSamba = groupNamesSamba.keys() userGroupNames = [] for userGr in userGroups: try: int(userGr) except: userGroupNames.append(userGr) continue flagFound = False for grName in grUnix.keys(): if grUnix[grName] == userGr: userGroupNames.append(grName) flagFound = True if not flagFound: for grName in grSamba.keys(): if grSamba[grName] == userGr: userGroupNames.append(grName) flagFound = True if not flagFound: gidNotFound.append(userGr) if gidNotFound: errorMessage = _("Groups numbers (%s) is not found in \ Samba and Unix services") %", ".join(gidNotFound) # Выдаем ошибку self.printERROR(errorMessage) return False # Если нет какой то из групп exclGroup=\ set(userGroupNames)^(set(groupNamesUnix)|set(groupNamesSamba)) if exclGroup: errorMessage = _("Groups (%s) is not found in \ Samba and Unix services") %", ".join(exclGroup) # Выдаем ошибку self.printERROR(errorMessage) return False else: if not rezultUnix: self.printERROR(errMessUnix) return False return (groupNamesUnix, groupNamesSamba) def searchSambaGroupName(self, groupName): """Находит группу сервиса Samba по её имени""" resSearch = self.searchLdapDN(groupName, self.relGroupsDN, "cn") return resSearch def searchGroupsSamba(self, userGroups, printError=True): """Ищет список групп из списка userGroups в LDAP Список групп может состоять из чисел или названий групп Возвращает (результат выполнения,словарь имен групп,сообщение о ошибке) """ userGroupNames = {} flagError = False gidErrors = [] groupErrors = [] for gid in userGroups: try: int(gid) except: groupName = gid res = self.searchSambaGroupName(groupName) if not res: groupErrors.append(groupName) flagError = True continue userGroupNames[res[0][0][1]['cn'][0]]=\ res[0][0][1]['gidNumber'][0] continue gidNumber = gid res = self.searchSambaGid(gidNumber) if not res: gidErrors.append(gidNumber) flagError = True continue userGroupNames[res[0][0][1]['cn'][0]] = res[0][0][1]['gidNumber'][0] if flagError: errorMessage = "" if groupErrors: errorGroup=_("Group names (%s) is not found in Samba service")\ %", ".join(groupErrors) errorMessage = errorGroup if printError: self.printERROR(errorGroup) if gidErrors: errorGid=_("Group numbers (%s) is not found in Samba service")\ %", ".join(gidErrors) errorMessage += errorGid if printError: self.printERROR(errorGid) return (False, userGroupNames, errorMessage) return (True, userGroupNames, "") def searchSambaGid(self, groupId): """Находит группу сервиса Samba по ёе id""" resSearch = self.searchLdapDN(str(groupId), self.relGroupsDN, "gidNumber") return resSearch def addUsersGroupSamba(self, users, groupName): """Добавляет пользователей из списка в Samba группу""" if not self.searchSambaGroupName(groupName): self.printERROR(_("group name is not found in Samba service")) return False flagFalse = False for userName in users: if not self.searchSambaUser(userName): self.printERROR(\ _("User %s is not found")%str(userName) ) flagFalse = True break if flagFalse: return False foundUsers = self.searchUsersInGroupSamba(users, groupName) addUsers = [] for user in users: if not(user in foundUsers): addUsers.append(user) modAttrs = [] for userName in addUsers: modAttrs.append((ldap.MOD_ADD, 'memberUid', userName)) if modAttrs: groupDN = self.addDN("cn="+groupName, self.relGroupsDN) return self.modAttrsDN(groupDN, modAttrs) return True @adminConnectLdap def addGroupSambaServer(self, groupName, options, printSuccess=True, checkSetup=True): """Добавляет группу пользователей Samba""" # Проверим установлен ли сервис samba if checkSetup and not self.initialChecks("samba"): return False # Если группа существует выходим без ошибки flagSearchGroups = True if options.has_key('f'): flagSearchGroups = False if flagSearchGroups and\ self.servUnixObj.searchGroupGroupName(groupName): self.printERROR(\ _("group name %s is found in") % str(groupName) +\ " /etc/group") return False if self.servUnixObj.searchUnixGroupName(groupName): self.printERROR(\ _("group name %s is found in Unix service") %\ str(groupName)) return False if self.searchSambaGroupName(groupName): self.printERROR(_("group name %s is found in Samba service") %\ str(groupName)) return False # Название группы self.clVars.Set("ur_group",groupName) # номер группы gid = str(self.servUnixObj.getMaxGid()) if options.has_key('g'): gid = options['g'] try: int(gid) except: self.printERROR(_("GID must be is number")) return False if flagSearchGroups and self.servUnixObj.searchGroupGid(gid): self.printERROR(_("GID is found in") + " /etc/group") return False if self.servUnixObj.searchUnixGid(gid): self.printERROR(_("GID is found in Unix service")) return False if self.searchSambaGid(gid): self.printERROR(_("GID is found in Samba service")) return False groupSid = "" # Получаем sid if options.has_key('s'): # Проверяем кoрректность sid sidRe = re.compile("^S-(?:\d+-)+\d+$") if not sidRe.search(options['s']): self.printERROR(_("SID incorrect")) return False groupSid = options['s'] else: sambaSid = self.getSambaSid() if not sambaSid: return False # Получаем samba rid sambaRid = str(2*int(gid)+1001) if options.has_key('r'): try: int(options['r']) except: self.printERROR(_("RID must be is number")) return False sambaRid = options['r'] # Получаем sid группы groupSid = "%s-%s" %(sambaSid,sambaRid) if not groupSid: self.printERROR(_("Group SID is empty")) return False # По умолчанию тип группы - доменная группа groupType = "2" if options.has_key('t'): try: int(options['t']) except: self.printERROR(_("group type must be is number")) return False if not options['t'] in ("2","4","5"): self.printERROR(_("group type incorrect")) self.printWARNING(_("Available values are")) self.printWARNING(_("2 (domain group), 4 (local group) and \ 5 (builtin group).")) self.printWARNING(_("The default group type is 2")) return False groupType = options['t'] self.clVars.Set("ur_group_sid", groupSid) self.clVars.Set("ur_group_type", groupType) self.clVars.Set("ur_group_id", gid) # Комментарий к группе gecos = self.servUnixObj.groupGecos if options.has_key('c'): gecos = options['c'] self.clVars.Set("ur_group_comment",gecos) ldifFile = self.ldifFileGroup groupLdif = self.createLdif(ldifFile) if not groupLdif: print self.getError() return False if not self.ldapObj.getError(): self.ldapObj.ldapAdd(groupLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False if options.has_key('p'): sys.stdout.write(gid) else: if printSuccess: self.printSUCCESS(_("Added group '%s' in Samba service")\ %groupName) return True def upgradeService(self): """Обновляет настройки и базу данных Используется при установке сервиса и его апдейте """ # Флаг ошибки flagError = False # Пользователь клиент Linux cl = self.staticUsers["client"] # Администратор сервиса Samba adm = self.staticUsers["admin"] # Удаляем группы admin, Computers. client из сервиса Unix oldRmGroupNames = ("admin","Computers","client") for rmGroupName in oldRmGroupNames: if self.servUnixObj.searchUnixGroupName(rmGroupName): if not self.servUnixObj.delGroupUnixServer(rmGroupName, {},False,False): flagError = True break # Добавляем статические Samba группы if not self.addStaticGroups(): return False # Меняем у админа и клиента номера первичных групп if not flagError: userObjs = (cl, adm) for obj in userObjs: if self.servUnixObj.searchUnixUser(obj.name): if not self.servUnixObj.modUserUnixServer(obj.name, {'g':obj.gid}, False, True): flagError = True break if not flagError: # Меняем у всех компьютеров первичную группу machineGroupName = self.clVars.Get('sr_samba_machine_group') resSearch = self.searchSambaGroupName(machineGroupName) if resSearch: machineGid = resSearch[0][0][1]['gidNumber'][0] else: mGr = self.staticGroups["Domain Computers"] machineGid = mGr.gid searchAllMachines = self.searchAllSambaMachines() if searchAllMachines: for data in searchAllMachines: machineName = data[0][1]['uid'][0] machineDN = self.addDN("uid=" + machineName, self.relComputersDN) res = self.modAttrsDN(machineDN, [(ldap.MOD_REPLACE, 'gidNumber', machineGid)]) if not res: self.printERROR(_("Can not replace machine %s \ 'gidNumber'")%machineName) flagError = True break if flagError: return False return True def modGroupSambaServer(self, groupName, options): """Модифицирует настройки группы пользователей LDAP""" # Проверим установлен ли сервис samba if not self.initialChecks("samba"): return False if not self.searchSambaGroupName(groupName): self.printERROR(_("group name not found in Samba service")) return False # Добавляем список пользователей в группу if options.has_key('a'): # добавляемые пользователи в группу users = options['a'].split(',') res = self.addUsersGroupSamba(users, groupName) if res: self.printSUCCESS(_("Appended list of users to group") + " " +\ str(groupName)) else: self.printERROR(_("Can not append list of users to group") +\ " " + str(groupName)) return False # Удаляем список пользователей из группы if options.has_key('d'): # удаляемые пользователи из группы users = options['d'].split(',') res = self.delUsersGroupSamba(users, groupName) if res: self.printSUCCESS(_("Deleted list users from group") + " " +\ str(groupName)) else: self.printERROR(_("Can not delete list users from group") +\ " " + str(groupName)) return False modGroupName = groupName # Изменяем имя группы if options.has_key('n'): newGroupName = options['n'] if self.servUnixObj.searchUnixGroupName(newGroupName): self.printERROR( _("group name %s is found in Unix service")%\ str(newGroupName)) return False if self.searchSambaGroupName(newGroupName): self.printERROR( _("group name %s is found in Samba service")%\ str(newGroupName)) return False newFirstDn = "cn=" + newGroupName oldDN = self.addDN("cn=" + groupName, self.relGroupsDN) res = self.modifyElemDN(oldDN, newFirstDn) if res: modGroupName = newGroupName self.printSUCCESS(_("Group renamed to %s")\ %newGroupName) else: self.printERROR(_("Can not rename group")) return False modAttrs = [] # Изменяем тип группы if options.has_key('t'): try: int(options['t']) except: self.printERROR(_("group type must be is number")) return False if not options['t'] in ("2","4","5"): self.printERROR(_("group type incorrect")) self.printWARNING(_("Available values are")) self.printWARNING(_("2 (domain group), 4 (local group) and \ 5 (builtin group).")) return False groupType = options['t'] modAttrs.append((ldap.MOD_REPLACE, 'sambaGroupType', groupType)) # Изменяем комментарий к группе if options.has_key('c'): gecos = options['c'] modAttrs.append((ldap.MOD_REPLACE, 'description', gecos)) modAttrs.append((ldap.MOD_REPLACE, 'displayName', gecos)) if modAttrs: groupDN = self.addDN("cn=" + modGroupName, self.relGroupsDN) res = self.modAttrsDN(groupDN, modAttrs) if res: if options.has_key('c'): self.printSUCCESS(_("Modified group comment")) if options.has_key('t'): self.printSUCCESS(_("Modified group type")) return True else: if options.has_key('c'): self.printERROR(_("Can not modify group comment")) if options.has_key('t'): self.printERROR(_("Can not modify group type")) return False return True def addMachineSambaServer(self, machineName, options): """Добавляет Samba машину в LDAP-сервер""" machineLogin = machineName.replace('$','') + "$" res = self.searchSambaMachine(machineLogin) if res: if res[0][0][1].has_key('sambaSID'): self.printERROR(_("machine")+" "+machineLogin+" "+\ "is found in Samba service") return True # добавляем Samba машину textLine = self.execProg("smbpasswd -a -m %s" %machineLogin) if textLine == False: self.printERROR(_("Can not add machine")) return False else: self.printSUCCESS(_("Added machine in Samba service")) return True else: # добавляем LDAP машину if not self.servUnixObj.addMachineLdapServer(machineLogin, options): return False # добавляем Samba машину textLine = self.execProg("smbpasswd -a -m %s" %machineLogin) if textLine == False: self.printERROR(_("Can not add machine")) return False else: self.printSUCCESS(_("Added machine in Samba service")) return True def getSambaSid(self): """Получаем Samba SID из LDAP""" resSearch = self.searchLdapDN("*", self.relDN, "sambaDomainName", ["sambaSID"]) if resSearch: return resSearch[0][0][1]['sambaSID'][0] self.printERROR(_("Not found sambaSID in LDAP")) return False def getAllowNet(self): """Получаем от пользователя доверительные сети и устанавливаем переменную профилей sr_samba_net_allow self.clVars должен быть определен """ print _("Enter the allowed ip addresses and network for %s service")\ %"Samba" + " (" + _("comma or space delimited") + ")" strPrompt = _("allow networks: ") netAllow = self.clVars.Get("sr_samba_net_allow") strNetAllow = "" if netAllow: strNetAllow = netAllow.replace(","," ") allowNet = self.getUserAllowNetwork(strPrompt, strNetAllow) if not allowNet: return False # Установка переменной доступные сети allowNet = ",".join(allowNet) self.clVars.Set("sr_samba_net_allow", allowNet ,True) return allowNet def setupSambaServer(self, options): """Начальная настройка Samba сервиса""" # Принудительная установка forceOptions = False # Создаем объект переменных и начальная проверка if not self.initialChecksSetup(): return False if options.has_key("f"): forceOptions = True if self.clVars.Get("sr_unix_set") != "on": self.printERROR(_("Unix service is not setuped")) self.printWARNING (_("Setup Unix service")) self.printWARNING(" cl-setup unix") return False # В случае если сервер установлен if self.clVars.Get("sr_samba_set") == "on" and\ not forceOptions: self.printWARNING (_("WARNING") + ": " +\ _("Samba server is configured")+ ".") return True # Доверительные сети по умолчанию allowNet = self.clVars.Get("os_net_allow") if not forceOptions: # предупреждение при выполнении этой программы будут изменены # конфигурационные файлы сервиса Samba self.printWARNING (_("WARNING") + ": " + _("Executing of the program will change") + " " + _("the configuration files of Samba service") + ".") # если вы готовы продолжить работу программы нажмите Y если нет n messDialog = \ _("If you are ready to continue executing the program")+", "+\ _("input 'yes'") +", "+ _("if not 'no'") if not self.dialogYesNo(messDialog): return True if options.has_key("a"): # Получаем от пользователя доверительные сети allowNet = self.getAllowNet() if not allowNet: return False else: if options.has_key("a"): # Получаем от пользователя доверительные сети allowNet = self.getAllowNet() if not allowNet: return False # делаем backup # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False bakupObj = servLdap() if not bakupObj.backupServer(): return False # Удаляем переменные сервиса в ini файлах self.deleteServiceVarsInFile("samba") # Cоздаем объект переменные self.createClVars() # Объект сервис репликации servReplObj = servRepl() foundReplication = False # проверяем на присутствие серверов репликации for replServ in servReplObj.replServices: if self.clVars.Get("ld_repl_%s_servers"%replServ): foundReplication = True break if not foundReplication: # Если серверов репликации нет # удаляем переменные репликации servReplObj.clVars = self.clVars servReplObj.deleteVars() # Cоздаем объект переменные self.createClVars() # Устанавливаем доступные сети self.clVars.Set("sr_samba_net_allow",allowNet,True) # Задаем рабочую группу (домен) if options.has_key("w"): workgroup = options['w'].strip() if len(workgroup)>15: self.printERROR(_("A very long name of the command line \ options '-w, --workgroup'")) return False self.clVars.Set("sr_samba_domain",workgroup) # Задаем netbios имя if options.has_key("n"): netbios = options['n'].strip() # Проверка на неравенство workgroup и netbios if options.has_key("w") and workgroup == netbios: self.printERROR(_("Value of command line option \ '-w, --workgroup' equal to value of command line option '-n, --netbios'")) return False self.clVars.Set("sr_samba_netbios",netbios) # Удаляем из автозапуска демона if not self.delDaemonAutostart("samba"): return False # Удаляем из share файл .replrun if not self.delReplFile(self.clVars): return False # останавливаем сервис Samba if not self.stopServices(["samba"]): return False # Имя устанавливаемого сервиса self.clVars.Set("cl_pass_service","samba") self.clVars.Write("sr_samba_set","off") # Cоздаем объект профиль устанавливая директорию samba для # файлов профилей if not self.applyProfilesFromService('samba'): return False # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False else: if not self.restartLdapServer(): return False # Записываем данные администратора сервиса Samba ldapParser = iniLdapParser() ldapParser.setVar("samba", {"DN":self.clVars.Get("ld_samba_dn"), "PASS":self.clVars.Get("ld_samba_pw")}) ldapParser = iniLdapParser() pswd = ldapParser.getVar("samba","PASS") if not pswd: self.printERROR(_("ERROR") + ": " +\ _("Samba admin password is not found")) return False textLine = self.execProg("smbpasswd -w %s" %(pswd)) if textLine == False: self.printERROR(_("ERROR") + ": " +\ _("Can not add Samba admin password")) return False # Рестарт LDAP сервера if not self.restartLdapServer(): return False #Cоединение с Ldap (администратор) if not shareLdap.getLdapObjInFile(self): return False resSearch = self.searchService() if resSearch: delDN = self.relDN if self.deleteDN(delDN): self.printOK(_("Removed Samba DN from LDAP Database") + " ...") else: self.printERROR(\ _("Can not remove Samba DN from LDAP Database")) return False # в случае отключения репликации if self.clVars.Get("ld_repl_set") != "on": # Объект сервис репликации servReplObj = servRepl() # Удаляем служебную ветку ldap if not servReplObj.delSysDN(): return False ldifFile = self.ldifFileBase baseLdif = self.createLdif(ldifFile) 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") + " ...") textLines = self.execProg("/etc/init.d/samba restart") if textLines == False: self.printNotOK(_("Starting") + " Samba ...") return False else: self.printOK(_("Starting") + " Samba ...") # Добавляем статические Samba группы и изменяем настройки if not self.upgradeService(): return False # Пользователь и группа для клиента Linux cl = self.staticUsers["client"] clGr = self.staticGroups["client"] # Администратор сервиса Samba и его группа adm = self.staticUsers["admin"] admGr = self.staticGroups["Administrators"] # Создаем клиента # Проверяем на наличие группы client resGroupClient = self.searchSambaGroupName(clGr.name) if not resGroupClient: opt = {} opt['c'] = clGr.comment opt['t'] = clGr.type if clGr.sid: opt['s'] = clGr.sid else: opt['r'] = clGr.rid opt['g'] = clGr.gid # Создаем Samba группу для пользователя client if not self.addGroupSambaServer(clGr.name, opt, False): self.printERROR(_("Can not created Samba group '%s'")\ %clGr.name) return False # Добавляем пользователя client для smb ресурса [remote] if not self.addUserSambaServer('client',{'f':'','u':cl.uid, 'c':'Client unix workstation','g':clGr.name, 's':'/bin/false','d':'/dev/null'},False,False): self.printERROR(_("not created samba user 'client'")) return False # Создаем админа # Проверяем на наличие группы admin resGroupAdmin = self.searchSambaGroupName(admGr.name) if not resGroupAdmin: opt = {} opt['c'] = admGr.comment opt['t'] = admGr.type if admGr.sid: opt['s'] = admGr.sid else: opt['r'] = admGr.rid opt['g'] = admGr.gid # Создаем Samba группу для пользователя admin if not self.addGroupSambaServer(admGr.name, opt, False): self.printERROR(_("Can not created Samba group '%s'")\ %admGr.name) return False # Добавляем пользователя admin if not self.addUserSambaServer('admin',{'f':'','u':adm.uid, 'c':'Administrator samba service','g':admGr.name, 's':'/bin/false','d':'/dev/null'},False,False): self.printERROR(_("not created samba user 'admin'")) return False # Если нет то создадим директорию /var/calculate/remote remoteEnvFile = self.clVars.Get("cl_env_path")[0] remotePath = os.path.split(remoteEnvFile)[0] if not os.path.exists(remotePath): os.makedirs(remotePath) # права и владелец /var/calculate/remote if os.path.exists(remotePath): os.chown(remotePath,0,int(cl.gid)) os.chmod(remotePath,02755) # изменяем владельца remote на client if not os.path.exists(remoteEnvFile): fd = os.open(remoteEnvFile, os.O_CREAT) os.close(fd) os.chmod(remoteEnvFile, 0640) if os.path.exists(remoteEnvFile): os.chown(remoteEnvFile,0,int(cl.gid)) if not self.setDaemonAutostart("slapd"): return False # Устанавливаем автозапуск демона if not self.setDaemonAutostart("samba"): return False # если нет share то создадим sharePath = self.clVars.Get("sr_samba_share_path") if not os.path.exists(sharePath): os.makedirs(sharePath) # Создадим иконку для share fileTxt = "[Desktop Entry]\nIcon=folder-favorites" fileDirectory = os.path.join(sharePath,".directory") uid = 0 gid = 0 if not self.createUserFile(fileDirectory, fileTxt, uid, gid): return False #запишем переменные для сервера domain = self.clVars.Get("sr_samba_domain") self.clVars.Write("sr_samba_domain",domain,True,"local") netbios = self.clVars.Get("sr_samba_netbios") self.clVars.Write("sr_samba_netbios",netbios,True,"local") allow = self.clVars.Get("sr_samba_net_allow") self.clVars.Write("sr_samba_net_allow",allow,True,"local") #запишем переменные для клиента fullHostName = "%s.%s"%(self.clVars.Get('os_net_hostname'), self.clVars.Get('os_net_domain')) self.clVars.Set("sr_samba_host",fullHostName,True) clientVars = ["sr_samba_host","ld_services_dn", "ld_unix_dn", "ld_bind_dn","ld_bind_pw","ld_base_dn","ld_samba_dn"] if not self.saveVarsClient(clientVars): return False self.clVars.Write("sr_samba_set","on") self.printOK(_("Samba service configured") + " ...") return True def modUserSambaPasswd(self, userName, options): # Проверим установлен ли сервис samba if not self.initialChecks("samba"): return False if not self.searchSambaUser(userName): self.printERROR( _("Samba user %s is not found")%str(userName)) return False # отключаем samba account if options.has_key('l'): textLine = self.execProg("smbpasswd -d %s" %(userName)) if textLine == False: self.printERROR(_("Can not disable Samba user")+ " "+\ str(userName)) return False else: self.printSUCCESS(_("Disabled Samba user %s")%str(userName)) # включаем Samba account if options.has_key('u'): textLine = self.execProg("smbpasswd -e %s" %(userName)) if textLine == False: self.printERROR(_("Can not enable Samba user")+ " "+\ str(userName)) return False else: self.printSUCCESS(_("Enabled Samba user %s")%str(userName)) if not options or options.has_key('s'): optPasswd = {"p":""} userPwd = self.getUserPassword(optPasswd, "p", False) if userPwd == False: return False if userPwd: # Опция s пароль только для Samba if not options.has_key('s'): if not self.servUnixObj.modUserUnixPasswd(userName,{}, userPwd): return False textLine = self.execProg("smbpasswd -a -s %s" %(userName), "%s\n%s\n" %(userPwd,userPwd)) if textLine == False: self.printERROR(_("Can not change Samba user password")) return False else: self.printSUCCESS( _("Samba password of user %s is changed")%\ str(userName)) return True return True def modUserSambaServer (self, userName, options, printSuccess=True): """Модифицирует настройки пользователя Samba в LDAP""" # Проверим установлен ли сервис samba if not self.initialChecks("samba"): return False # Находим Samba пользователя res = self.searchSambaUser(userName) if not res: self.printERROR( _("Samba user %s is not found in Samba service")%\ str(userName)) return False # отключаем Samba account if options.has_key('L'): textLine = self.execProg("smbpasswd -d %s" %(userName)) if textLine == False: self.printERROR(_("Can not disable Samba user")+ " "+\ str(userName)) return False else: self.printSUCCESS(_("Disabled Samba user %s")%str(userName)) # включаем samba account elif options.has_key('U'): textLine = self.execProg("smbpasswd -e %s" %(userName)) if textLine == False: self.printERROR(_("Can not enable Samba user")+ " "+\ str(userName)) return False else: self.printSUCCESS(_("Enabled Samba user %s")%str(userName)) # модифицируем пароль if options.has_key('P') or options.has_key('p'): pwDialog = [_("New SMB password"), _("Retype new SMB password")] userPwd = self.getUserPassword(options, "p", "P", pwDialog) if userPwd == False: return False # Опция s пароль только для Samba if not options.has_key('s'): if not self.servUnixObj.modUserUnixPasswd(userName,{}, userPwd): return False textLine = self.execProg("smbpasswd -s %s" %(userName), "%s\n%s\n" %(userPwd,userPwd)) if textLine == False: self.printERROR(_("Can not modify Samba user password")) return False self.printSUCCESS(_("Modified Samba user password")) if options.has_key("g"): optUnix = {'g':options['g']} if not self.servUnixObj.modUserUnixServer(userName, optUnix, True, True): return False # изменяем Unix и Samba группы в которые включен пользователь if options.has_key("G"): # Изменяем Samba группы пользователя userGroups = options['G'].split(',') data = self.searchUnixAndSambaGroups(userGroups, True) if data and type(data) == types.TupleType: userGroupNamesUnix, userGroupNamesSamba = data else: return False if userGroupNamesUnix: optUnix = {'G':",".join(userGroupNamesUnix)} # Изменяем Unix группы пользователя if not self.servUnixObj.modUserUnixServer(userName, optUnix,False, True): return False # Удаляем Samba группы у пользователя if not self.delUserInGroup(userName): return False flagError = False for group in userGroupNamesSamba: if not self.addUsersGroupSamba([userName], group): flagError = True break if flagError: return False if printSuccess: self.printSUCCESS(_("Replaced list of supplementary group")) # Изменяем комментарий к пользователю if options.has_key('c'): comment = options['c'] if res[0][0][1].has_key('displayName'): modAttrs = [(ldap.MOD_REPLACE, 'displayName', comment)] else: modAttrs = [(ldap.MOD_ADD, 'displayName', comment)] DN = self.addDN("uid="+userName, self.relUsersDN) if not self.modAttrsDN(DN, modAttrs): return False self.printSUCCESS(_("Modified comment")) return True class servLdap(shareLdap): """Методы севисa Ldap""" # Сервисы которым не нужен LDAP notLdapServices = ["dhcp"] # Базовый ldif файл ldifFileBase = "/usr/lib/calculate/calculate-server/ldif/base.ldif" # Для backup # Директория куда будет сохранен архив backupDirectory = "/var/calculate/server-backup/ldap" # ldif файл базы LDAP archLdifFile = "/tmp/LDAP_DATABASE.ldif" # ldif файл базы LDAP для сервиса Unix replArchLdifFileUnix = "/tmp/REPL_LDAP_DATABASE_UNIX.ldif" # список файлов в архиве для сервиса Unix replListFileUnix = "/tmp/REPL_LIST_FILES_UNIX.txt" # ldif файл базы LDAP для сервиса Samba replArchLdifFileSamba = "/tmp/REPL_LDAP_DATABASE_SAMBA.ldif" # список файлов в архиве для сервиса Samba replListFileSamba = "/tmp/REPL_LIST_FILES_SAMBA.txt" # ldif файл базы LDAP для сервиса Mail replArchLdifFileMail="/tmp/REPL_LDAP_DATABASE_MAIL.ldif" # список файлов в архиве для сервиса Mail replListFileMail = "/tmp/REPL_LIST_FILES_MAIL.txt" # ldif файл базы LDAP для сервиса Mail, Samba replArchLdifFileMailSamba="/tmp/REPL_LDAP_DATABASE_MAIL_SAMBA.ldif" # список файлов в архиве для сервиса Mail, Samba replListFileMailSamba = "/tmp/REPL_LIST_FILES_MAIL_SAMBA.txt" # ldif файл базы LDAP для сервиса Mail, Unix replArchLdifFileMailUnix = "/tmp/REPL_LDAP_DATABASE_MAIL_UNIX.ldif" # список файлов в архиве для сервиса Mail, Unix replListFileMailUnix = "/tmp/REPL_LIST_FILES_MAIL_UNIX.txt" # приватная директория Samba sambaPrivate = "/var/lib/samba/private" # директория c алиасами сервиса Mail mailPrivate = "/etc/mail" # название файла где будет храниться список архивируемых файлов tmpListFile = "/tmp/list_CDS_files.txt" # Директория для хранения профилей backup backupDir = "backup" # LDAP ldapDbConfig = "/var/lib/openldap-data/DB_CONFIG" ldapDbConfigExample = "/etc/openldap/DB_CONFIG.example" # Директории хранения сертификатов сервиса Mail sslDirsMail = ["/etc/ssl/dovecot","/etc/ssl/postfix"] # Файл сертификата сервиса jabber sslJabberFile = "/etc/jabber/ssl.pem" # директория для хранения временных файлов tmpEnvDir = "/tmp/tmp_calculate" def __init__(self): shareLdap.__init__(self) # Сервис Samba self.servSambaObj = servSamba() # Сервис Mail self.servMailObj = servMail() # Сервис Jabber self.servJabberObj = servJabber() # Сервис Proxy self.servProxyObj = servProxy() # Сервис DHCP self.servDhcpObj = servDhcp() def savePrivateFile(self, fileName, data): """Записать файл с правами 0600""" try: FD = open (fileName, "w+") FD.close() os.chmod(fileName,0600) FD = open (fileName, "w+") FD.write(data) FD.close() except: return False return True def rebuildServer(self, options): """Перегенерирует конфигурационные файлы, и базу данных LDAP""" bFile = self.getArchFile() if not bFile: return False self.printSUCCESS(_("Used backup file %s")%str(bFile)) archFileTime = time.localtime(os.stat(bFile)[stat.ST_MTIME]) timeFile = datetime.datetime(archFileTime[0],archFileTime[1], archFileTime[2],archFileTime[3], archFileTime[4],archFileTime[5]) localTime = time.localtime() timeLocal = datetime.datetime(localTime[0],localTime[1], localTime[2],localTime[3], localTime[4],localTime[5]) if timeLocal < timeFile: self.printERROR(_("Incorrect system time or time create file %s")\ %bFile) return False deltaTime = timeLocal - timeFile if deltaTime.days == 0: deltaSec = deltaTime.seconds dHours = int(deltaSec/3600) dMinutes = int((deltaSec - dHours*3600)/60) dSeconds = deltaSec - dHours*3600 - dMinutes*60 hours = _("hours") minutes = _("minutes") seconds = _("seconds") if dHours: timeBackup = "%s %s %s %s %s %s"%\ (dHours,hours,dMinutes,minutes,dSeconds,seconds) elif dMinutes: timeBackup = "%s %s %s %s"%(dMinutes,minutes,dSeconds,seconds) elif dSeconds: timeBackup = "%s %s"%(dSeconds,seconds) self.printWARNING(_("The backup file is created %s ago")%timeBackup) else: self.printWARNING(_("The backup file is created %s days ago")\ %deltaTime.days) self.printWARNING(_("cl-rebuld uses a file backup, make sure it is not \ outdated. If the backup is obsolete, use cl-backup-server.")) messDialog = \ _("If you are ready to continue executing the program")+", "+\ _("input 'yes'") +", "+ _("if not 'no'") if not self.dialogYesNo(messDialog): return True # В случае создания сервера репликации из файла backup c # другого компьютера replServices = [] if options.has_key("repl"): # Находим имена сервисов репликации для этого сервера # и инициализируем переменные replServices = self.getArchReplServices() if not replServices: return False # Cоздаем объект репликации objRepl = servRepl() # Определяем поддерживает ли openldap репликацию if not objRepl.supportReplOpenldap(self.clVars): return False if not self.restoreServer(False,replServices): return False # Изменяем и сохраняем переменные if not objRepl.prepAndSaveEnv(): return False else: # Восстанавливаем сервисы не запуская их # и не прописывая в автозагрузку if not self.restoreServer(False): return False verbose = False opt = {} if options.has_key("v"): opt['v'] = '' if options.has_key("a"): opt['a'] = '' # Сервисы для которых не будет задаваться вопрос о доступных сетях # при включенной опции allow noInputAllowNetServices = [] if "samba" in replServices: noInputAllowNetServices = ["samba"] if not self.updateServer(opt, "all", False, noInputAllowNetServices): return False self.printOK(_("Rebuilding all services") + " ...") return True def rebuildLdapServer(self, options): """Перегенерирует конфигурационные файлы, и базу данных LDAP""" return self.rebuildServer(options) def applyProfilesFromService(self, service, verbose=False, dirsFilter = [], filesFilter = []): """Применяем профили для данного сервиса""" # Cоздаем объект профиль устанавливая директорию # service для файлов профилей clProf = cl_profile.profile(self.clVars,service,dirsFilter,filesFilter) # Объединяем профили data = clProf.applyProfiles() if clProf.getError(): self.printERROR(clProf.getError()) return False else: if verbose and type(data) == types.TupleType: dirs, files = data return files return True def updateIDReplServers(self): """Обновление id серверов репликации для LDAP""" if self.clVars.Get("ld_repl_set") == "on": replIds = self.clVars.Get("ld_repl_ids") self.reloadDefaultVar("ld_repl_ids") newReplIds = self.clVars.Get("ld_repl_ids") if replIds != newReplIds: self.clVars.Write("ld_repl_ids",newReplIds, True,"local") return True def updateServer(self, options, serviceUpdate, clVars=False, noInputAllowNetServices=[], printReplServ=True): """Перегенерируем конфигурационные файлы определенного или всех сервисов """ # Создаем переменные if clVars: self.clVars = clVars else: self.createClVars() if self.clVars.Get('sr_mail_history') == 'on': self.servicesDaemons['mail'] += ['sortmilter'] # В случае некорректно включенной репликации if self.clVars.Get("ld_repl_set") == "on" and\ not self.clVars.Get("ld_repl_id"): self.printERROR(_("Incorrect set Replication")) self.printERROR(_("Not found 'serverID' this server")) self.printERROR(_("variable 'ld_repl_id' empty")) return False if printReplServ and self.clVars.Get("ld_repl_set") == "on": # Вывод списка реплицируемых cерверов unixReplServ = self.clVars.Get("ld_repl_unix_servers") sambaReplServ = self.clVars.Get("ld_repl_samba_servers") mailReplServ = self.clVars.Get("ld_repl_mail_servers") if unixReplServ: self.printSUCCESS(\ _("Replication servers for service Unix: %s")\ %", ".join(unixReplServ.split(","))) if sambaReplServ: self.printSUCCESS(\ _("Replication servers for service Samba: %s")\ %", ".join(sambaReplServ.split(","))) if mailReplServ: self.printSUCCESS(_("Replication servers for service Mail: %s")\ %", ".join(mailReplServ.split(","))) # Настройка прокси if serviceUpdate in ["all","proxy"]: # Порт для прокси сервера if options.has_key("p"): proxyPort = options['p'] try: numberProxyPort = int(proxyPort) except: self.printERROR(_("Option '-p' is not number")) return False proxyPort = str(numberProxyPort) self.clVars.Set("sr_proxy_port", proxyPort, True) if options.has_key("host"): fullHostName = options['host'] if not "." in fullHostName: fullHostName = "%s.%s" %(fullHostName, self.clVars.Get('os_net_domain')) self.clVars.Set("sr_proxy_host",fullHostName,True) # Настройка почты if serviceUpdate in ["all","mail"]: # Создаем сертификат для Dovecot if not self.createMailCertificate(): return False history,history_domain,history_path = \ self.getMailHistoryData(options) if options.has_key("t"): mailType = options['t'] if mailType: if not set(mailType.split(",")) <= set(["imap","pop3"]): self.printERROR(\ _("Мail type not 'imap' or 'pop3' or 'pop3,imap'")) return False if len(mailType.split(",")) == 2: mailType = "all" else: self.printERROR(_("Мail type incorrect")) return False self.clVars.Set("sr_mail_type", mailType) if options.has_key("c"): mailCrypt = options['c'] if not mailCrypt in ["none", "tls"]: self.printERROR(_("Мail encryption not 'none' or 'tls'")) return False if mailCrypt == "none": mailCrypt = "" self.clVars.Set("sr_mail_crypt", mailCrypt, True) # Настройка jabber cервиса # Предыдущее имя хоста для Jabber previousJabberHost = self.clVars.Get("sr_jabber_host") if serviceUpdate in ["all","jabber"]: # Устанавливаем основной хост jabber cервиса if not self.createJabberCertificate(): return False if options.has_key("host"): newHostName = options['host'] if not "." in newHostName: newHostName = "%s.%s" %(newHostName, self.clVars.Get('os_net_domain')) if newHostName != previousJabberHost: # Устанавливаем перемемнную self.clVars.Set("sr_jabber_host",newHostName,True) hosts = self.clVars.Get("sr_jabber_hosts").split(",") unicHostsList = [self.clVars.Get("sr_jabber_host")] for host in hosts: if not host in [newHostName, previousJabberHost]: unicHostsList.append(host) jabberHosts = ",".join(unicHostsList) self.clVars.Set("sr_jabber_hosts",jabberHosts,True) # Устанавливаем дополнительные хосты jabber cервиса if options.has_key("hosts"): hosts = options['hosts'].split(",") jabberHostsList = [self.clVars.Get("sr_jabber_host")] for host in hosts: apHost = host if not "." in host: apHost = "%s.%s" %(host, self.clVars.Get('os_net_domain')) jabberHostsList.append(apHost) unicHostsList = [] for host in jabberHostsList: if not host in unicHostsList: unicHostsList.append(host) jabberHosts = ",".join(unicHostsList) self.clVars.Set("sr_jabber_hosts",jabberHosts,True) # находим установленные сервисы servInstalled = self.getServiceSetup() # Все установленные сервисы allServSetup = servInstalled if not servInstalled: self.printERROR("Services are not installed") return False flagError = False if serviceUpdate=="all": pass elif serviceUpdate in servInstalled: servInstalled = [serviceUpdate] else: if not serviceUpdate: self.printERROR(_("Service incorrect")) else: self.printERROR(_("Service %s not installed")%serviceUpdate) return False ldapParser = iniLdapParser() # Установка переменных for service in servInstalled: if service == "ldap": continue servicePwd = service if service == "dhcp": if not "dns" in allServSetup: continue servicePwd = "dns" adminPw = ldapParser.getVar(servicePwd,"PASS") if not adminPw: self.printERROR(_("Not found password from service %s")\ %servicePwd) flagError = True break self.clVars.Set("ld_%s_pw"%servicePwd, adminPw, True) # Наложение профилей verbose = False if options.has_key("v"): verbose = True # Cервисы которые рестартуют servicesRestart = [] # Флаг почтового релея flagMailRelay = False if not flagError: # Обновление id серверов репликации self.updateIDReplServers() for service in servInstalled: if service == "ldap": continue if service == "samba": # Получаем от пoльзователя доверительные сети # для сервиса Samba if options.has_key("a") and\ not service in noInputAllowNetServices: self.servSambaObj.clVars = self.clVars if not self.servSambaObj.getAllowNet(): flagError = True break # Добавляем файл в директорию share в случае репликации # сервиса Samba sharePath = self.clVars.Get("sr_samba_share_path") # Файл для определения к какому из серверов # подключился клиент fileReplRun = os.path.join(sharePath,".reprun") # если нет share то создадим if not os.path.exists(sharePath): os.makedirs(sharePath) # Путь иконки share fileDirectory = os.path.join(sharePath,".directory") # Прочтем файл иконки share if os.path.exists(fileDirectory): FD = open(fileDirectory, "r") iconTxt = FD.read() FD.close() # Если старая иконка то удаляем ее if "Icon=folder-bookmarks" in iconTxt: os.remove(fileDirectory) # Создадим иконку для share fileTxt = "[Desktop Entry]\nIcon=folder-favorites" if not os.path.exists(fileDirectory): uid = 0 gid = 0 if not self.createUserFile(fileDirectory, fileTxt, uid, gid): flagError = True break if self.clVars.Get("ld_repl_samba_set") == "on": # Добавляем в share файл .reprun if not self.servSambaObj.addReplFile(self.clVars): flagError = True break else: # Удаляем из share файл .reprun if not self.servSambaObj.delReplFile(self.clVars): flagError = True break if service == "mail": # Получаем от пользователя доверительные сети # для сервиса Mail if options.has_key("a") and\ not service in noInputAllowNetServices: self.servMailObj.clVars = self.clVars if not self.servMailObj.getAllowNet(): flagError = True break # В случае почтового релея if self.clVars.Get("ld_repl_mail_set") == "on" and\ self.clVars.Get("sr_mail_relay_set") == "on": flagMailRelay = True if service == "proxy": # Получаем от пользователя доверительные сети # для сервиса Proxy if options.has_key("a") and\ not service in noInputAllowNetServices: self.servProxyObj.clVars = self.clVars if not self.servProxyObj.getAllowNet(): flagError = True break # Наложение профилей if not flagError: if flagMailRelay: files = self.applyProfilesFromService(service, verbose, ["/etc/dovecot", "/etc/ssl/dovecot"], ["/etc/procmailrc", "/etc/postfix/ldap-aliases-gr.cf", "/etc/postfix/ldap-aliases.cf", "/etc/postfix/ldap-recipient-gr.cf", "/etc/postfix/ldap-recipient.cf"]) else: files = self.applyProfilesFromService(service, verbose) if not files: flagError = True break if verbose and type(files) == types.ListType: self.printSUCCESS(_("Updating config from service %s")\ %self.printNameService(service)) for applyFile in files: self.printWARNING(applyFile) else: self.printOK(_("Updating config from service %s")\ %self.printNameService(service) + " ...") if flagMailRelay: service = "mail_relay" servicesRestart.append(service) # Перезапускаем ldap if not flagError: service = "ldap" if (not os.path.exists(self.ldapDbConfig) and os.path.exists(self.ldapDbConfigExample)): with open(self.ldapDbConfig, 'w') as fout: fout.write(open(self.ldapDbConfigExample,'r').read()) if not self.restartLdapServer(): return False # Устанавливаем автозапуск демона if not self.setDaemonAutostart("slapd"): return False self.printOK(_("Restarting service %s")%"LDAP" + " ...") # Перезапускаем остальные сервисы if not flagError: for service in servicesRestart: if service in "ldap": continue if service in "mail": if not self.servMailObj.addDefaultMailGroup(): return False if not self.stopServices([service]): flagError = True break if self.clVars.Get('sr_mail_history') == 'on': self.servicesDaemons['mail'] += ['sortmilter'] elif 'sortmilter' in self.servicesDaemons['mail']: self.servicesDaemons['mail'].remove('sortmilter') if not self.startServices([service], False): flagError = True break if service == "mail_relay": service = "mail" # Название сервиса для вывода на экран servicePrn = self.printNameService(service) self.printOK(_("Restarting service %s")%servicePrn +\ " ...") # настраиваем автозапуски if self.clVars.Get('sr_mail_history') == 'on': self.setDaemonAutostart("sortmilter") else: self.delDaemonAutostart("sortmilter") if not flagError and "samba" in servInstalled and\ serviceUpdate in ["all","samba"]: # Добавляем статические Samba группы и изменяем настройки if not self.servSambaObj.upgradeService(): flagError = True if not flagError and serviceUpdate in ["all","jabber"]: # Замена имени хоста для сервиса Jabber в LDAP if options.has_key("host"): if self.clVars.Get("sr_jabber_host") != previousJabberHost: # Установка в LDAP ветке Jabber cервиса нового имени хоста if not self.servJabberObj.setHostName(newHostName, previousJabberHost): return False # Update jabberID записей в сервисе Unix и изменение сn записей if not self.servJabberObj.upgradeService(): return False if not flagError and "dhcp" in servInstalled and\ serviceUpdate in ["all","dhcp"]: # Создаем файл вывода ошибок скрипта dhcp if not self.servDhcpObj.createLogFile(): flagError = True # Создаем DNS зоны на основании информации в # конфигурационном файле сервиса DHCP (dhcpd.conf) if not flagError and not self.servDhcpObj.upgrageDNSZones(): flagError = True if not flagError and serviceUpdate in ["all","unix","samba","mail"]: # создаем объект репликации objRepl = servRepl() # В случае репликации if self.clVars.Get("ld_repl_id") and\ self.clVars.Get("ld_repl_set") == "on": # Если не почтовый релей if not flagMailRelay: # Добавляем в крон скрипт для чистки директорий if not objRepl.cronReplicationON(): return False else: # Удаляем из крона скрипт для чистки директорий if not objRepl.cronReplicationOFF(): return False # Добавляем ветку репликации if not objRepl.addReplDN(self.clVars): return False else: # Удаляем из крона скрипт для чистки директорий if not objRepl.cronReplicationOFF(): return False # Удаляем служебную ветку ldap if not objRepl.delSysDN(): return False # запишем переменные для сервера if not flagError: # Переменные для jabber if "jabber" in servInstalled and serviceUpdate in ["all","jabber"]: self.clVars.Write("sr_jabber_history", self.clVars.Get("sr_jabber_history"), True,"local") self.clVars.Write("sr_jabber_host", self.clVars.Get("sr_jabber_host"), True,"local") self.clVars.Write("sr_jabber_hosts", self.clVars.Get("sr_jabber_hosts"), True,"local") # Переменные для почты if "mail" in servInstalled and serviceUpdate in ["all","mail"]: self.clVars.Write("sr_mail_type", self.clVars.Get("sr_mail_type"), True,"local") self.clVars.Write("sr_mail_crypt", self.clVars.Get("sr_mail_crypt"), True,"local") self.clVars.Write("sr_mail_net_allow", self.clVars.Get("sr_mail_net_allow"), True,"local") self.clVars.Write("sr_mail_history", self.clVars.Get("sr_mail_history"), True,"local") self.clVars.Write("sr_mail_history_domain", self.clVars.Get("sr_mail_history_domain"), True,"local") self.clVars.Write("sr_mail_history_path", self.clVars.Get("sr_mail_history_path"), True,"local") #запишем переменные для клиента if self.clVars.Get("sr_mail_type") == "all": self.clVars.Set("sr_mail_type","imap") clientVars = ["sr_mail_type", "sr_mail_crypt"] if not self.saveVarsClient(clientVars): return False # Переменные для Samba if "samba" in servInstalled and serviceUpdate in ["all","samba"]: self.clVars.Write("sr_samba_net_allow", self.clVars.Get("sr_samba_net_allow"), True,"local") #запишем переменные для клиента clientVars = ["ld_samba_dn"] if not self.saveVarsClient(clientVars): return False # Переменные для Proxy if "proxy" in servInstalled and serviceUpdate in ["all","proxy"]: self.clVars.Write("sr_proxy_net_allow", self.clVars.Get("sr_proxy_net_allow"), True,"local") self.clVars.Write("sr_proxy_host", self.clVars.Get("sr_proxy_host"), True,"local") self.clVars.Write("sr_proxy_port", self.clVars.Get("sr_proxy_port"), True,"local") #запишем переменные для клиента clientVars = ["sr_proxy_host","sr_proxy_port"] if not self.saveVarsClient(clientVars): return False if flagError: return False else: return True def updateLdapServer(self, options, serviceUpdate): """Обновление сервисов""" return self.updateServer(options ,serviceUpdate) def scanServiceDirs(self, serviceName): """На основании имени сервиса выдает список файлов от корня""" clProf = cl_profile.profile(self.clVars) foundFiles = clProf.scanProfiles(serviceName) if not foundFiles: return [] foundFiles = filter(lambda x: os.path.exists(x), foundFiles) return foundFiles def backupNotLdap(self): """Сохраняет только настройки установленных сервисов""" # создаем директорию backup-а if not os.path.exists(self.backupDirectory): try: os.makedirs(self.backupDirectory) except os.IOError: self.printERROR(_("Can not create directory") + ": " +\ str(self.backupDirectory)) return False # генерируем название файла архива strData = time.strftime("%Y%m%d%H%M%S",time.localtime(time.time())) backupFile = "%s.tar.bz2" %strData # если существуют удаляем файлы в /tmp self.removeTmpFiles() # Создаем объект хранения переменных если необходимо if not self.clVars: self.createClVars() # находим установленные сервисы servInstalled = self.getServiceSetup() if not servInstalled: self.printERROR("unable to create a backup") self.printERROR("Services are not installed") return False listIncorrectServices = list(set(servInstalled)-\ set(self.notLdapServices)) if listIncorrectServices: self.printERROR(_("LDAP service is not setuped")) self.printERROR(_("Services %s need LDAP service")\ %", ".join(listIncorrectServices)) self.printERROR(_("Can not create backup file")) return False # Все файлы которые нужно заархивировать allArchFiles = [] flagError = False for serviceName in servInstalled: archFiles = self.scanServiceDirs(serviceName) if archFiles == False: flagError = True break allArchFiles += archFiles if flagError: self.printERROR("Error create list archive files") return False scanPrivDirs = [] # Cоздаем файловый объект fileObj = cl_profile._file() # Добавляем calculate.env iniFiles = self.clVars.Get("cl_env_path") if iniFiles: for iniFile in iniFiles: if os.path.exists(iniFile): allArchFiles.append(iniFile) profileDirs = self.clVars.Get("cl_profile_path") if profileDirs: profileDirs = profileDirs[1:] for pDir in profileDirs: if os.path.exists(pDir): scanPrivDirs.append(pDir) # Сканируем директории if scanPrivDirs: dirObjs = fileObj.scanDirs(scanPrivDirs) for dirObj in dirObjs: for archFile in dirObj.files: allArchFiles.append(archFile) allArchFiles = self.unicList(allArchFiles) # Сохраняем файл список архивируемых файлов if not self.savePrivateFile (self.tmpListFile, "\n".join(allArchFiles)): self.printERROR(_("Can not create list archive files") + ": " +\ str(self.tmpListFile)) return False bFile = os.path.join(self.backupDirectory, backupFile) strCmd = "tar --files-from=%s -cjf %s" %(self.tmpListFile, bFile) retTar = self.execProg(strCmd) if retTar == False: self.printERROR(_('Can not execute "%s"')%strCmd) return False # если существуют удаляем файлы в /tmp self.removeTmpFiles() if os.path.exists(bFile): os.chmod(bFile,0600) self.printSUCCESS(_("Created archive file") + ": " +\ str(bFile)) return True else: self.printERROR(_("Can not create archive file") + ": " +\ str(bFile)) return False def backupServer(self): """Сохраняет настройки установленных сервисов и базу LDAP""" # создаем директорию backup-а if not os.path.exists(self.backupDirectory): try: os.makedirs(self.backupDirectory) except os.IOError: self.printERROR(_("Can not create directory") + ": " +\ str(self.backupDirectory)) return False # Соединяемся с LDAP if not shareLdap.getLdapObjInFile(self): return False # получаем ldif текст всей базы LDAP ldifText = self.fullElementDNtoText() if not ldifText: self.printERROR(_("LDAP database empty")) return False replServices = [] # ldif тексты для сервисов ldifTextUnix = "" ldifTextMailUnix = "" ldifTextSamba = "" ldifTextMailSamba = "" ldifTextMail = "" # В случае включения репликации создаем ldif файлы для сервисов if self.clVars.Get("ld_repl_set") == "on": if self.clVars.Get("sr_mail_set") == "on" and\ self.clVars.Get("ld_repl_mail_set") == 'on': # получаем ldif текст для сервиса Mail ldifTextMail = self.fullElementMailDNtoText() if not ldifTextMail: self.printERROR(_("LDAP database empty")) return False if not 'mail' in replServices: replServices.append('mail') if self.clVars.Get("sr_unix_set") == "on" and\ self.clVars.Get("ld_repl_unix_set") == 'on': # получаем ldif текст для сервиса Unix ldifTextUnix = self.fullElementUnixDNtoText() if not ldifTextUnix: self.printERROR(_("LDAP database empty")) return False replServices.append('unix') if self.clVars.Get("sr_mail_set") == "on" and\ self.clVars.Get("ld_repl_mail_set") == 'on': # получаем ldif текст для сервиса Mail,Unix ldifTextMailUnix = self.fullElementMailUnixDNtoText() if not ldifTextMailUnix: self.printERROR(_("LDAP database empty")) return False if not 'mail' in replServices: replServices.append('mail') if self.clVars.Get("sr_samba_set") == "on" and\ self.clVars.Get("ld_repl_samba_set") == 'on': # получаем ldif текст для сервиса Samba ldifTextSamba = self.fullElementSambaDNtoText() if not ldifTextSamba: self.printERROR(_("LDAP database empty")) return False replServices.append('samba') if self.clVars.Get("sr_mail_set") == "on" and\ self.clVars.Get("ld_repl_mail_set") == 'on': # получаем ldif текст для сервиса Mail,Samba ldifTextMailSamba = self.fullElementMailSambaDNtoText() if not ldifTextMailSamba: self.printERROR(_("LDAP database empty")) return False if not 'mail' in replServices: replServices.append('mail') # генерируем название файла архива strData = time.strftime("%Y%m%d%H%M%S",time.localtime(time.time())) backupFile = "%s.tar.bz2" %strData # если существуют удаляем файлы в /tmp self.removeTmpFiles() # находим установленные сервисы servInstalled = self.getServiceSetup() if not servInstalled: self.printERROR("unable to create a backup") self.printERROR("Services are not installed") return False # Все файлы которые нужно заархивировать allArchFiles = [] flagError = False for serviceName in servInstalled: archFiles = self.scanServiceDirs(serviceName) if archFiles == False: flagError = True break allArchFiles += archFiles if flagError: self.printERROR("Error create list archive files") return False scanPrivDirs = [] # файлы в архиве для Unix replArchFilesUnix = [] # сканируемые директории для Unix replScanPrivDirsUnix = [] # файлы в aрхиве для Samba replArchFilesSamba = [] # сканируемые директории для Samba replScanPrivDirsSamba = [] # файлы в aрхиве для Mail replArchFilesMail = [] # сканируемые директории для Mail replScanPrivDirsMail = [] # файлы в aрхиве для Mail, Unix replArchFilesMailUnix = [] # файлы в aрхиве для Mail, Samba replArchFilesMailSamba = [] # В случае включения репликации if replServices: for service in servInstalled: if service == "unix": archFiles = self.scanServiceDirs(service) if archFiles == False: flagError = True break # файлы в архиве для Unix replArchFilesUnix = archFiles elif service == "samba": archFiles = self.scanServiceDirs(service) if archFiles == False: flagError = True break # файлы в aрхиве для Samba replArchFilesSamba = archFiles if service == "mail": archFiles = self.scanServiceDirs(service) if archFiles == False: flagError = True break # файлы в aрхиве для Mail replArchFilesMail = archFiles if flagError: self.printERROR("Error create list archive files for \ service %s")%service return False # Cоздаем файловый объект fileObj = cl_profile._file() if "ldap" in servInstalled: # Получаем путь к ini директории ldapParser = iniLdapParser() #iniPath = ldapParser.pathIniFile #scanPrivDirs.append(iniPath) ## Добавляем удаленных пользователей #dirDelUsers = self.clVars.Get("sr_deleted_path") #if os.path.exists(dirDelUsers): #scanPrivDirs.append(dirDelUsers) # Добавляем calulate.ldap allArchFiles.append(ldapParser.nameIniFile) if os.path.exists(self.ldapDbConfig): allArchFiles.append(self.ldapDbConfig) if replServices: if "unix" in replServices: replArchFilesUnix.append(ldapParser.nameIniFile) if "samba" in replServices: replArchFilesSamba.append(ldapParser.nameIniFile) if "mail" in replServices: replArchFilesMail.append(ldapParser.nameIniFile) # Добавляем calculate.env iniFiles = self.clVars.Get("cl_env_path") if iniFiles: for iniFile in iniFiles: if os.path.exists(iniFile): allArchFiles.append(iniFile) if replServices: if "unix" in replServices: replArchFilesUnix.append(iniFile) if "samba" in replServices: replArchFilesSamba.append(iniFile) if "mail" in replServices: replArchFilesMail.append(iniFile) profileDirs = self.clVars.Get("cl_profile_path") if len(profileDirs)>1: profileDirs = profileDirs[1:] if "samba" in servInstalled: # Добавляем в архивацию профили клиента profileDirs.append('/var/calculate/remote/client-profile') for pDir in profileDirs: if os.path.exists(pDir): scanPrivDirs.append(pDir) if replServices: if "unix" in replServices: replScanPrivDirsUnix.append(pDir) if "samba" in replServices: replScanPrivDirsSamba.append(pDir) if "mail" in replServices: replScanPrivDirsMail.append(pDir) if "samba" in servInstalled: scanPrivDirs.append(self.sambaPrivate) if replServices and "samba" in replServices: replScanPrivDirsSamba.append(self.sambaPrivate) if "mail" in servInstalled: scanPrivDirs.append(self.mailPrivate) # Добавляем в директории сканирования директории сертификатов mail scanPrivDirs += self.sslDirsMail if replServices and "mail" in replServices: replScanPrivDirsMail.append(self.mailPrivate) # Добавляем в директории сканирования директории сертификатов # mail replScanPrivDirsMail += self.sslDirsMail # При включении репликации сканируем директории if replServices: if "samba" in replServices and replScanPrivDirsSamba: dirObjs = fileObj.scanDirs(replScanPrivDirsSamba) for dirObj in dirObjs: for archFile in dirObj.files: replArchFilesSamba.append(archFile) if "unix" in replServices and replScanPrivDirsUnix: dirObjs = fileObj.scanDirs(replScanPrivDirsUnix) for dirObj in dirObjs: for archFile in dirObj.files: replArchFilesUnix.append(archFile) if "mail" in replServices and replScanPrivDirsMail: dirObjs = fileObj.scanDirs(replScanPrivDirsMail) for dirObj in dirObjs: for archFile in dirObj.files: replArchFilesMail.append(archFile) # Сканируем директории if scanPrivDirs: dirObjs = fileObj.scanDirs(scanPrivDirs) for dirObj in dirObjs: for archFile in dirObj.files: allArchFiles.append(archFile) # Добавляем сертификат jabber if "jabber" in servInstalled: allArchFiles.append(self.sslJabberFile) # Добавляем resolv.conf и hosts в случае dhcpd if "dhcp" in servInstalled: allArchFiles.append(self.servDhcpObj.resolvFile) allArchFiles.append(self.servDhcpObj.hostsFile) if replServices: additFiles = [] if "unix" in replServices: # Дополнительные файлы добавляемые в архив additFilesUnix = [self.replArchLdifFileUnix, self.replListFileUnix] additFiles = list(set(additFilesUnix)|set(additFiles)) for additFile in additFilesUnix: replArchFilesUnix.append(additFile) replArchFilesUnix = self.unicList(replArchFilesUnix) # Удаляем начальный "/" replArchFilesUnix = map(lambda x:\ "/".join(filter(lambda y:y ,x.split("/"))),replArchFilesUnix) replArchFilesUnix.sort() if "samba" in replServices: # Дополнительные файлы добавляемые в архив additFilesSamba = [self.replArchLdifFileSamba, self.replListFileSamba] additFiles = list(set(additFilesSamba)|set(additFiles)) for additFile in additFilesSamba: replArchFilesSamba.append(additFile) replArchFilesSamba += replArchFilesUnix # Удаляем начальный "/" replArchFilesSamba = map(lambda x:\ "/".join(filter(lambda y:y ,x.split("/"))),replArchFilesSamba) replArchFilesSamba = self.unicList(replArchFilesSamba) replArchFilesSamba.sort() if "mail" in replServices: # Дополнительные файлы добавляемые в архив additFilesMail = [self.replArchLdifFileMail, self.replListFileMail] additFiles = list(set(additFilesMail)|set(additFiles)) for additFile in additFilesMail: replArchFilesMail.append(additFile) if "unix" in replServices: additFilesMailUnix = [self.replArchLdifFileMailUnix, self.replListFileMailUnix] additFiles = list(set(additFilesMailUnix)|set(additFiles)) for additFile in additFilesMailUnix: replArchFilesMailUnix.append(additFile) replArchFilesMailUnix = map(lambda x:\ "/".join(filter(lambda y:y ,x.split("/"))),\ replArchFilesMailUnix) replArchFilesMailUnix = self.unicList(replArchFilesMailUnix) replArchFilesMailUnix.sort() if "samba" in replServices: additFilesMailSamba = [self.replArchLdifFileMailSamba, self.replListFileMailSamba] additFiles = list(set(additFilesMailSamba)|set(additFiles)) for additFile in additFilesMailSamba: replArchFilesMailSamba.append(additFile) replArchFilesMailSamba = map(lambda x:\ "/".join(filter(lambda y:y ,x.split("/"))),\ replArchFilesMailSamba) replArchFilesMailSamba=self.unicList(replArchFilesMailSamba) replArchFilesMailSamba.sort() # Удаляем начальный "/" replArchFilesMail = map(lambda x:\ "/".join(filter(lambda y:y ,x.split("/"))),replArchFilesMail) replArchFilesMail = self.unicList(replArchFilesMail) replArchFilesMail.sort() for additFile in additFiles: allArchFiles.append(additFile) allArchFiles.append(self.archLdifFile) allArchFiles = self.unicList(allArchFiles) # В случае репликации сохраняем файлы (список файлов, ldif - файл) if replServices: if "samba" in replServices: if not self.savePrivateFile (self.replListFileSamba, "\n".join(replArchFilesSamba)): self.printERROR(_("Can not create list archive files")+\ ": " + str(self.replListFileSamba)) return False if not self.savePrivateFile(self.replArchLdifFileSamba, ldifTextSamba): self.printERROR(_("Can not create ldif file") + ": " +\ str(self.replArchLdifFileSamba)) return False if "unix" in replServices: if not self.savePrivateFile (self.replListFileUnix, "\n".join(replArchFilesUnix)): self.printERROR(_("Can not create list archive files")+\ ": " + str(self.replListFileUnix)) return False if not self.savePrivateFile(self.replArchLdifFileUnix, ldifTextUnix): self.printERROR(_("Can not create ldif file") + ": " +\ str(self.replArchLdifFileUnix)) return False if "mail" in replServices: # в случае включения репликации для сервисов # Mail, Unix if set(["mail","unix"]) <= set(replServices): replArchFilesMailUnix = list(\ set(replArchFilesMail)|set(replArchFilesUnix)|\ set(replArchFilesMailUnix)) # Сортируем файлы replArchFilesMailUnix.sort() if not self.savePrivateFile(self.replListFileMailUnix, "\n".join(replArchFilesMailUnix)): self.printERROR(_("Can not create list archive files")+\ ": " + str(self.replListFileMailUnix)) return False if not self.savePrivateFile(self.replArchLdifFileMailUnix, ldifTextMailUnix): self.printERROR(_("Can not create ldif file") + ": " +\ str(self.replArchLdifFileMailUnix)) return False # в случае включения репликации для сервисов # Mail, Samba if set(["mail","samba"]) <= set(replServices): replArchFilesMailSamba = list(\ set(replArchFilesMail)|set(replArchFilesSamba)|\ set(replArchFilesMailSamba)) # Сортируем файлы replArchFilesMailSamba.sort() if not self.savePrivateFile(self.replListFileMailSamba, "\n".join(replArchFilesMailSamba)): self.printERROR(_("Can not create list archive files")+\ ": " + str(self.replListFileMailSamba)) return False if not self.savePrivateFile(self.replArchLdifFileMailSamba, ldifTextMailSamba): self.printERROR(_("Can not create ldif file") + ": " +\ str(self.replArchLdifFileMailSamba)) return False # Удаляем dovecot, procmailrc из списка файлов # а также ненужные алиасы replArchFilesMail = map(lambda x:"/".join(x),\ filter(lambda x:\ not 'dovecot' in x and\ not 'procmailrc' == x[-1] and\ not 'ldap-aliases-gr.cf' == x[-1] and\ not 'ldap-aliases.cf' == x[-1] and\ not 'ldap-recipient-gr.cf' == x[-1] and\ not 'ldap-recipient.cf' == x[-1],\ map(lambda x:x.split("/"),replArchFilesMail))) if not self.savePrivateFile (self.replListFileMail, "\n".join(replArchFilesMail)): self.printERROR(_("Can not create list archive files")+\ ": " + str(self.replListFileMail)) return False if not self.savePrivateFile(self.replArchLdifFileMail, ldifTextMail): self.printERROR(_("Can not create ldif file") + ": " +\ str(self.archLdifFileMail)) return False #Сохраняемые файлы в случае почтового релея if self.clVars.Get("sr_mail_set") == "on" and\ self.clVars.Get("ld_repl_mail_set") == 'on' and\ self.clVars.Get("sr_mail_relay_set") == "on": dirsFilter = ["/etc/dovecot", "/etc/ssl/dovecot"] filesFilter = ["/etc/procmailrc", "/etc/postfix/ldap-aliases-gr.cf", "/etc/postfix/ldap-aliases.cf", "/etc/postfix/ldap-recipient-gr.cf", "/etc/postfix/ldap-recipient.cf"] files = [] for fileName in allArchFiles: dirName, fileN = os.path.split(fileName) if not dirName in dirsFilter and\ not fileName in filesFilter: files.append(fileName) allArchFiles = files # Сохраняем файл список архивируемых файлов if not self.savePrivateFile (self.tmpListFile, "\n".join(allArchFiles)): self.printERROR(_("Can not create list archive files") + ": " +\ str(self.tmpListFile)) return False # Сохраняем ldif-файл базы LDAP if not self.savePrivateFile(self.archLdifFile, ldifText): self.printERROR(_("Can not create ldif file") + ": " +\ str(self.archLdifFile)) return False bFile = os.path.join(self.backupDirectory, backupFile) strCmd = "tar --files-from=%s -cjf %s" %(self.tmpListFile, bFile) retTar = self.execProg(strCmd) if retTar == False: self.printERROR(_('Can not execute "%s"')%strCmd) return False # если существуют удаляем файлы в /tmp self.removeTmpFiles() if os.path.exists(bFile): os.chmod(bFile,0600) self.printSUCCESS(_("Created archive file") + ": " +\ str(bFile)) return True else: self.printERROR(_("Can not create archive file") + ": " +\ str(bFile)) return False def backupLdapServer(self, options): if not options or (options and options.has_key("b")): # Создаем объект переменных clVars self.createClVars(self.clVars) # находим установленные сервисы servInstalled = self.getServiceSetup() if not servInstalled: self.printERROR("unable to create a backup") self.printERROR("Services are not installed") return False listServicesLDAP = list(set(servInstalled)-\ set(self.notLdapServices)) if listServicesLDAP: return self.backupServer() else: return self.backupNotLdap() if options.has_key("r"): return self.restoreServer() def startAllSetupServices(self): """Запускаем все работающие установленные сервисы а также прописываем в автозапуск """ # находим установленные сервисы servInstalled = self.getServiceSetup() # Если почтовый релей и установлен только Mail сервис то # заменяем mail на mail_relay if set(["mail","ldap"]) == set(servInstalled) and\ self.clVars.Get("sr_mail_relay_set") == "on": servInstalled = filter(lambda x: x!="mail",servInstalled) +\ ["mail_relay"] return self.startServices(servInstalled) def getArchFile(self): """Возвращает имя архивного файла из директории backup """ if not os.path.exists(self.backupDirectory): self.printERROR(_("Path for backup is not found") + ": " +\ str(self.backupDirectory)) return False # Получаем номер архивного файла archFiles = os.listdir(self.backupDirectory) maxFileNumber = 0 for archFile in archFiles: numbTxt = archFile.split(".")[0] try: numb = int(numbTxt) except: continue if maxFileNumber3 and archFile[-4:] == ".env": envFiles.append(archFile) if not envFiles: self.printERROR(_("Inside the archive %s no files with \ the extension '.env'")%bFile) return False if flagError: self.printERROR(_("Can not list the contents of an archive") +\ ": " + str(bFile)) return False # Удаляем временные файлы self.removeTmpFiles() # Сохраняем файл - список извлекаемых файлов if not self.savePrivateFile (self.tmpListFile, "\n".join(envFiles)): self.printERROR(_("Can not create list extract files") + ": " +\ str(self.tmpListFile)) return False # Cоздаем временную директорию try: os.makedirs(self.tmpEnvDir) except os.IOError: self.printERROR(_("Can not create directory") + ": " +\ str(self.tmpEnvDir)) return False # Разархивируем env файлы во временную директорию if self.execProg("tar -C %s --files-from=%s -xjf %s"\ %(self.tmpEnvDir,self.tmpListFile, bFile)) == False: self.printERROR(_("Can not extract archive") + ": " + str(bFile)) return False # Создаем объект переменных clVars self.clVars = cl_base.DataVars() self.clVars.flServer() #Записываем новые пути к env в переменную envPaths = [] for path in envFiles: envPaths.append(os.path.join(self.tmpEnvDir,path)) self.clVars.Set("cl_env_path", envPaths, True) # считаем переменные из ini файлов self.clVars.flIniFile() # Установленные сервисы servInstalled = self.getServiceSetup() if not servInstalled: self.printERROR("Services are not installed in archive %s" %bFile) return False # Найдем сервисы которые нужно установить replSambaServers = self.clVars.Get("ld_repl_samba_servers") if replSambaServers: replSambaServers = replSambaServers.split(",") replUnixServers = self.clVars.Get("ld_repl_unix_servers") if replUnixServers: replUnixServers = replUnixServers.split(",") replMailServers = self.clVars.Get("ld_repl_mail_servers") if replMailServers: replMailServers = replMailServers.split(",") hostName = self.clVars.Get('os_net_hostname') domain = self.clVars.Get('os_net_domain') services = [] # Найден ли в списке серверов репликации текущий сервер flagFoundReplServer = False fullHostName = "%s.%s"%(hostName,domain) if not fullHostName in replSambaServers: if fullHostName in replUnixServers: flagFoundReplServer = True if self.replListFileUnix[1:] in listReplFiles: services = ["unix"] if fullHostName in replMailServers: if self.replListFileMailUnix[1:] in listReplFiles: services = ["unix", "mail"] else: flagFoundReplServer = True if self.replListFileSamba[1:] in listReplFiles: services = ["unix", "samba"] if fullHostName in replMailServers: if self.replListFileMailSamba[1:] in listReplFiles: services = ["unix", "samba", "mail"] if not services and fullHostName in replMailServers: flagFoundReplServer = True if self.replListFileMail[1:] in listReplFiles: services = ["mail"] # Удаляем временные файлы self.removeTmpFiles() if flagFoundReplServer: if not services: self.printERROR(_("Inside the archive %s no files \ for running replication")%bFile) return False else: self.printERROR(\ _("Not found this replication server %s in backup file")%fullHostName) return False return services def restoreServer(self, startServices=True, replServices=False): """Восстанавливает из архива все установленные сервисы Восстановленные сервисы будут запущены """ bFile = self.getArchFile() if not bFile: return False # Создаем объект переменных clVars self.createClVars() # останавливаем все настроенные сервисы и удаляем их демонов из # автозапуска insServices = self.getServiceSetup() if not self.stopServices(insServices) or \ not self.delServicesAutostart(insServices): return False # Проверяем архив на содержание в нем LDAP flagArchLdap = self.isLdapArchive(bFile) # Удаляем старую базу данных if not self.removeLdapDatabase(): return False # Если архив содержит LDAP данные tarCommand = "tar -C / --transform 's|etc/calculate|var/lib/calculate|' " if flagArchLdap: # Накладываем профили (берем из папки backup) if not self.applyProfilesFromService(self.backupDir): self.printERROR(_("Can not apply profile")+ ": backup") return False # Запускаем LDAP сервер if not self.runLdapServer(): return False # Соединяемся с LDAP временным пользователем if not self.connectLdapServer(): return False # Cписок разахивированных файлов (файл ldif) allArchFiles = [self.archLdifFile[1:]] if replServices: if set(["samba", "mail"]) <= set(replServices): allArchFiles = [self.replArchLdifFileMailSamba, self.replListFileMailSamba] elif set(["unix", "mail"]) <= set(replServices): allArchFiles = [self.replArchLdifFileMailUnix, self.replListFileMailUnix] elif "samba" in replServices: allArchFiles = [self.replArchLdifFileSamba, self.replListFileSamba] elif "unix" in replServices: allArchFiles = [self.replArchLdifFileUnix, self.replListFileUnix] elif "mail" in replServices: allArchFiles = [self.replArchLdifFileMail, self.replListFileMail] # Удаляем начальный '/' allArchFiles = map(lambda x:\ "/".join(filter(lambda y:y ,x.split("/"))),allArchFiles) # Удаляем временные файлы self.removeTmpFiles() # Сохраняем файл - список извлекаемых файлов (файл ldif) if not self.savePrivateFile (self.tmpListFile, "\n".join(allArchFiles)): self.printERROR(_("Can not create list extract files") + ": " +\ str(self.tmpListFile)) return False # Распаковываем ldif файл ldifFile = self.archLdifFile if replServices: if set(["samba", "mail"]) <= set(replServices): ldifFile = self.replArchLdifFileMailSamba elif set(["unix", "mail"]) <= set(replServices): ldifFile = self.replArchLdifFileMailUnix elif "samba" in replServices: ldifFile = self.replArchLdifFileSamba elif "unix" in replServices: ldifFile = self.replArchLdifFileUnix elif "mail" in replServices: ldifFile = self.replArchLdifFileMail if self.execProg("tar -C / --files-from=%s -xjf %s"\ %(self.tmpListFile, bFile)) == False: self.printERROR(_("Can not extract archive") + ": "+str(bFile)) return False if not os.path.exists(ldifFile): self.printERROR(_("Ldif file is not found") + " :" +\ str(ldifFile)) return False # Читаем ldif файл FD = open(ldifFile, "r") ldif = FD.read() FD.close() # Добавляем в базу из ldif self.ldapObj.ldapAdd(ldif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False # Останавливаем LDAP сервер if not self.stopLdapServer(): return False # Удаляем временные файлы нужные для установки сервисов self.removeTmpRestoreFile() if replServices: # Файл - список разархивируемых файлов listReplFile = "" if set(["samba", "mail"]) <= set(replServices): listReplFile = self.replListFileMailSamba elif set(["unix", "mail"]) <= set(replServices): listReplFile = self.replListFileMailUnix elif "samba" in replServices: listReplFile = self.replListFileSamba elif "unix" in replServices: listReplFile = self.replListFileUnix elif "mail" in replServices: listReplFile = self.replListFileMail else: self.printERROR(_("Not supported replication service %s")\ %replServices[0]) return False if self.execProg(tarCommand + "--files-from=%s -xjf %s"\ %(listReplFile, bFile)) == False: self.printERROR(_("Can not extract archive") +\ ": "+str(bFile)) return False else: # Распаковываем целиком архив if self.execProg(tarCommand + "-xjf %s" %(bFile)) == False: self.printERROR(_("Can not extract archive") +\ ": "+str(bFile)) return False self.changeHostname() else: # Распаковываем целиком архив if self.execProg(tarCommand + "-xjf %s" %(bFile)) == False: self.printERROR(_("Can not extract archive") + ": "+str(bFile)) return False self.changeHostname() # Удаляем временные файлы self.removeTmpFiles() # считаем переменные из ini файлов self.clVars.flIniFile() # останавливаем все инсталлируемые сервисы и удаляем их демонов из # автозапуска insServices = self.getServiceSetup() if not self.stopServices(insServices) or \ not self.delServicesAutostart(insServices): return False if startServices: # Стартуем все сервисы и прописываем в автозагрузку if not self.startAllSetupServices(): return False self.printOK(_("Restored all installed services") + " ...") if replServices: self.printOK(_("Replication on, for services (%s)")\ %", ".join(replServices) + " ...") return True def changeHostname(self): """ Меняем имя хоста на имя в /etc/hosts """ with open('/etc/hosts','r') as f: hosts_data = f.read() hostname_ = re.search("^127.0.0.1\s+([^.]+)", hosts_data, flags=re.M) if hostname_: hostname = hostname_.group(1) hostname_fn = "/proc/sys/kernel/hostname" old_hostname = open(hostname_fn, 'r').read().strip() if old_hostname != hostname: with open("/proc/sys/kernel/hostname",'w') as f: f.write(hostname) def removeTmpFiles(self): """Удаляем временные файлы""" removeFiles=[self.tmpListFile,self.archLdifFile, self.replArchLdifFileUnix,self.replListFileUnix, self.replArchLdifFileSamba,self.replListFileSamba, self.replArchLdifFileMail,self.replListFileMail, self.replArchLdifFileMailSamba,self.replListFileMailSamba, self.replArchLdifFileMailUnix,self.replListFileMailUnix] for rmFile in removeFiles: if os.path.exists(rmFile): os.remove(rmFile) if os.path.exists(self.tmpEnvDir): self.removeDir(self.tmpEnvDir) def __del__(self): """Удаляем временные файлы""" self.removeTmpFiles() def removeTmpRestoreFile(self): """Удаляем временные файлы нужные для восстановления сервисов""" profilePath = self.clVars.Get("cl_profile_path")[0] backupDir = os.path.join(profilePath, self.backupDir) fileObj = cl_profile._file() scanObjs = fileObj.scanDirs([backupDir]) if not scanObjs: return True #удаляем файлы for fileRemove in scanObjs[0].files: rmFile = fileRemove.split(backupDir)[1] if os.path.exists(rmFile): os.remove(rmFile) #удаляем ссылки for linkRemove in scanObjs[0].links: rmLink = flinkRemove.split(backupDir)[1] if os.path.exists(rmLink): os.unlink(rmLink) return True def removeLdapDatabase(self): """Удаляем предыдущую базу данных""" pathDatabase = "/var/lib/openldap-data" if os.listdir(pathDatabase): strCmd = "rm -rf %s/*"%pathDatabase if self.execProg(strCmd) == False: self.printERROR(_('Can not execute "%s"')%strCmd) 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 = self.genSleep() while ldapObj.getError(): try: # Задержка wait.next() except StopIteration: break # Очистка ошибки cl_profile._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) cl_profile._error.error = listError self.printERROR(_("Can not connected to LDAP server")) return False return True def setupLdapServer(self, options): """Начальная настройка LDAP сервиса""" # Принудительная установка forceOptions = False self.createClVars() if options.has_key("f"): forceOptions = True if self.clVars.Get("sr_ldap_set") == "on" and\ not forceOptions: self.printWARNING (_("WARNING") + ": " +\ _("LDAP server is configured")+ ".") return True if not forceOptions: # предупреждение при выполнении этой программы будут изменены # конфигурационные файлы и база данных сервиса 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 self.dialogYesNo(messDialog): return True else: # делаем backup # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False if not self.backupServer(): return False # останавливаем сервисы # Удаляем из автозапуска демона if not self.delDaemonAutostart("slapd"): return False # Останавливаем все установленные сервисы if not self.stopServices(self.getALLServices()): return False # Удаляем из автозагрузки все установленные сервисы if not self.delServicesAutostart(self.getALLServices()): return False # Удаляем из крона скрипт для чистки удаленых пользователей # создаем объект репликации objRepl = servRepl() if not objRepl.cronReplicationOFF(): return False # Удаляем из share файл .replrun if not self.servSambaObj.delReplFile(self.clVars): return False # Получим пути к ini файлам iniFiles = self.clVars.Get("cl_env_path") # Удаляем секции настроек из всех ini for iniFile in iniFiles: if os.path.exists(iniFile): if "remote" in iniFile: cl_base.iniParser(iniFile).delArea("client") else: cl_base.iniParser(iniFile).delArea("server") # Получим путь к ldap файлу ldapParser = iniLdapParser() ldapFile = ldapParser.nameIniFile # Удаляем ldap файл if os.path.exists(ldapFile): os.remove(ldapFile) # Имя устанавливаемого сервиса self.clVars.Set("cl_pass_service","ldap") self.clVars.Write("sr_ldap_set","off") # Первый проход self.clVars.Set("cl_pass_step","1",True) if not self.applyProfilesFromService('ldap'): self.printERROR(_("Can not apply profiles") +":"+ _("first pass")) return False # Удаляем старую базу данных if not self.removeLdapDatabase(): return False # Запускаем LDAP сервер if not self.runLdapServer(): 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 not self.applyProfilesFromService('ldap'): self.printERROR(_("Can not apply profiles") +":"+ _("second pass")) return False if (not os.path.exists(self.ldapDbConfig) and os.path.exists(self.ldapDbConfigExample)): with open(self.ldapDbConfig, 'w') as fout: fout.write(open(self.ldapDbConfigExample,'r').read()) # Перезапускаем LDAP сервер if not self.restartLdapServer(): return False # Записываем данные администратора сервера ldapParser.setVar("admin", {"DN":self.clVars.Get("ld_admin_dn"), "PASS":self.clVars.Get("ld_admin_pw")}) # Устанавливаем автозапуск демона if not self.setDaemonAutostart("slapd"): return False # Записываем переменные для пользователя clientVars = ["ur_organization", "ur_signature"] if not self.saveVarsClient(clientVars): return False self.clVars.Write("sr_ldap_set","on") self.printOK(_("LDAP service configured") + " ...") return True class cl_ldap(shareLdap): """Основной класс для работы с LDAP""" def __init__(self, cmdName): shareLdap.__init__(self) # объект для форматированного вывода imp_cl_help.__init__(self, cmdName) servName = "" if "user" in cmdName: servName = _("user") elif "group" in cmdName: servName = _("group") elif "setup" in cmdName: servName = _("service") elif "update" in cmdName: servName = _("service") self.chapter = [\ # расположение разделов на странице # имя раздела, видимый или невидимый, кол. "\n" после # названия раздела, кол. "\n" после раздела # тип раздела ("Copyright",False,0,2,""), (_("Usage"),True,0,1,""), ("Function",False,0,2,""), (_("Examples"),True,1,1,""), (_("Common options"),True,1,1,"options"), (_("LDAP service options"),True,1,1,"options"), (_("Unix service options"),True,1,1,"options"), (_("Samba service options"),True,1,1,"options"), (_("Mail service options"),True,1,1,"options"), (_("Jabber service options"),True,1,1,"options"), (_("FTP service options"),True,1,1,"options"), (_("Proxy service options"),True,1,1,"options"), (_("DNS service options"),True,1,1,"options"), (_("DHCP service options"),True,1,1,"options"), (_("Services"),True,1,0,"") ] # имена используемых программ и их номера для доступа к переменным # self.data self.progName = { 'cl-groupadd':0, 'cl-groupdel':1, 'cl-groupmod':2, 'cl-useradd':3, 'cl-userdel':4, 'cl-usermod':5, 'cl-setup':6, 'cl-passwd':7, 'cl-backup-server':8, 'cl-update-server':9, 'cl-rebuild':10, 'execserv':11, 'cl-replication':12, 'replcron':13, 'cl-info':14, 'proxy':15, 'cl-dns-recadd':16, 'cl-dns-recdel':17, 'cl-dns-recmod':18, 'cl-dns-zoneadd':19, 'cl-dns-zonedel':20, 'cl-dns-zonemod':21, 'cl-dhcp-netadd':22, 'cl-dhcp-netdel':23, 'cl-dhcp-netmod':24, 'cl-dhcp-hostadd':25, 'cl-dhcp-hostdel':26, 'cl-dhcp-hostmod':27, 'dhcp':28, } # Cвязь сервисов и действующих опций self.relServices = {"samba":[_("Common options"), _("Samba service options")], "ldap":[_("Common options"), _("LDAP service options")], "unix":[_("Common options"), _("Unix service options")], "mail":[_("Common options"), _("Mail service options")], "jabber":[_("Common options"), _("Jabber service options")], "ftp":[_("Common options"), _("FTP service options")], "proxy":[_("Common options"), _("Proxy service options")], "dns":[_("Common options"), _("DNS service options")], "dhcp":[_("Common options"), _("DHCP service options")], } # Cвязь длинных опций помощи и выводимых разделов помощи с опциями self.relOptions = {"h":[_("Common options")], "help-ldap":[_("Common options"), _("LDAP service options")], "help-unix":[_("Common options"), _("Unix service options")], "help-samba":[_("Common options"), _("Samba service options")], "help-mail": [_("Common options"), _("Mail service options")], "help-jabber":[_("Common options"), _("Jabber service options")], "help-ftp":[_("Common options"), _("FTP service options")], "help-proxy":[_("Common options"), _("Proxy service options")], "help-dns":[_("Common options"), _("DNS service options")], "help-dhcp":[_("Common options"), _("DHCP service options")], "help-all":[_("Common options"), _("Samba service options"), _("LDAP service options"), _("Unix service options"), _("Mail service options"), _("Jabber service options"), _("FTP service options"), _("Proxy service options"), _("DNS service options"), ] } # список разделов, которые на наличие в ней информации # используется для автоматического отображения/скрытия # опций help-имя # Пример: self.relOption = # { "help-all":[_("Common options"], _("Unix service options"), # _("Samba service options"), _("LDAP service options")}] # self.relChapterPass = (_("Common options"),) # это означается что опция будет активна, если только в разделах # кроме Common options есть хоть одна доступная опция. self.relChapterPass = (_("Common options"),) self.data = [\ # Options {'shortOption':"h", 'longOption':"help", 'helpChapter':_("Common options"), 'help':_("display this help and exit") }, {'longOption':"help-all", 'helpChapter':_("Common options"), 'help':_("display help for all services options") }, {'longOption':"help-jabber", 'helpChapter':_("Common options"), 'help':_("display help for Jabber service options") }, {'progAccess':(6,), 'longOption':"help-ldap", 'helpChapter':_("Common options"), 'help':_("display help for LDAP service options") }, {'longOption':"help-mail", 'helpChapter':_("Common options"), 'help':_("display help for Mail service options") }, {'longOption':"help-samba", 'helpChapter':_("Common options"), 'help':_("display help for Samba service options") }, {'longOption':"help-unix", 'helpChapter':_("Common options"), 'help':_("display help for Unix service options") }, {'longOption':"help-ftp", 'helpChapter':_("Common options"), 'help':_("display help for FTP service options") }, {'longOption':"help-proxy", 'helpChapter':_("Common options"), 'help':_("display help for Proxy service options") }, {'longOption':"help-dns", 'helpChapter':_("Common options"), 'help':_("display help for DNS service options") }, {'longOption':"help-dhcp", 'helpChapter':_("Common options"), 'help':_("display help for DHCP service options") }, {'progAccess':(0,), 'shortOption':"f", 'longOption':"force", 'helpChapter':_("Unix service options"), 'help':_("does not check system group") }, {'progAccess':(0,), 'shortOption':"g", 'longOption':"gid", 'optVal':"GID", 'helpChapter':_("Unix service options"), 'help':_("use GID for the new group") }, {'progAccess':(0,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Unix service options"), 'help':_("set the description field for the new group") }, {'progAccess':(0,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Mail service options"), 'help':_("set the description field for the new group") }, {'progAccess':(0,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Jabber service options"), 'help':_("set the description field for the new group") }, {'progAccess':(0,), 'shortOption':"p", 'helpChapter':_("Unix service options"), 'help':_("print the gidNumber to stdout") }, {'progAccess':(0,), 'shortOption':"e", 'longOption':"alt-emails", 'optVal':"ALT_EMAILS", 'helpChapter':_("Mail service options"), 'help':_("set alternate email addresses for the new mail group") }, {'progAccess':(0,), 'longOption':"hide", 'optVal':"HIDE_HOSTS", 'helpChapter':_("Mail service options"), 'help':_("host names mail servers who have no access to emails \ to this group (comma delimited)") }, {'progAccess':(0,), 'shortOption':"f", 'longOption':"force", 'helpChapter':_("Samba service options"), 'help':_("does not check system group") }, {'progAccess':(0,), 'shortOption':"g", 'longOption':"gid", 'optVal':"GID", 'helpChapter':_("Samba service options"), 'help':_("use GID for the new group") }, {'progAccess':(0,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Samba service options"), 'help':_("set the description field for the new group") }, {'progAccess':(0,), 'shortOption':"r", 'longOption':"rid", 'optVal':"RID", 'helpChapter':_("Samba service options"), 'help':_("set the group rid for the new group") }, {'progAccess':(0,), 'shortOption':"t", 'longOption':"type", 'optVal':"TYPE", 'helpChapter':_("Samba service options"), 'help':_("set the group type for the new group.\n\ Available values are 2 (domain group), 4 (local group) and 5 (builtin group).\n\ The default group type is 2.") }, {'progAccess':(0,), 'shortOption':"p", 'helpChapter':_("Samba service options"), 'help':_("print the gidNumber to stdout") }, {'progAccess':(0,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Proxy service options"), 'help':_("set the description field for the new group") }, {'progAccess':(0,), 'shortOption':"p", 'longOption':"port", 'optVal':"PORTS", 'helpChapter':_("Proxy service options"), 'help':_("set the port or port range for the new group") }, {'progAccess':(2,), 'shortOption':"a", 'longOption':"add", 'optVal':"USERS", 'helpChapter':_("Common options"), 'help':_("add members (comma delimited)") }, {'progAccess':(2,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Common options"), 'help':_("set the description field for the new group") }, {'progAccess':(2,), 'shortOption':"d", 'longOption':"delete", 'optVal':"USERS", 'helpChapter':_("Common options"), 'help':_("delete members (comma delimited)") }, {'progAccess':(2,), 'shortOption':"n", 'longOption':"new-name", 'optVal':"NEW_GROUP", 'helpChapter':_("Common options"), 'help':_("force use NEW_GROUP name by GROUP") }, {'progAccess':(2,), 'shortOption':"t", 'longOption':"type", 'optVal':"TYPE", 'helpChapter':_("Samba service options"), 'help':_("set the group type.\n\ Available values are 2 (domain group), 4 (local group) and 5 (builtin group).") }, {'progAccess':(2,), 'shortOption':"e", 'longOption':"alt-emails", 'optVal':"ALT_EMAILS", 'helpChapter':_("Mail service options"), 'help':_("set alternate email addresses for the mail group") }, {'progAccess':(2,), 'longOption':"hide", 'optVal':"HIDE_HOSTS", 'helpChapter':_("Mail service options"), 'help':_("host names mail servers who have no access to emails \ to this group (comma delimited)") }, {'progAccess':(2,), 'longOption':"hide-off", 'helpChapter':_("Mail service options"), 'help':_("clear host names mail servers who have no access to emails \ to this group") }, {'progAccess':(3,), 'shortOption':"b", 'longOption':"base-dir", 'optVal':"BASE_DIR", 'helpChapter':_("Unix service options"), 'help':_("base directory for the new user account home directory") }, {'progAccess':(3,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Unix service options"), 'help':_("set the COMMENT field for the new user account") }, {'progAccess':(3,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("FTP service options"), 'help':_("set the COMMENT field for the new user account") }, {'progAccess':(3,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Samba service options"), 'help':_("set the COMMENT field for the new account") }, {'progAccess':(3,), 'shortOption':"e", 'longOption':"alt-emails", 'optVal':"ALT_EMAILS", 'helpChapter':_("Mail service options"), 'help':_("set alternate email addresses for the new mail account") }, {'progAccess':(3,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Mail service options"), 'help':_("set the COMMENT field for the new account") }, {'progAccess':(3,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Jabber service options"), 'help':_("set the COMMENT field for the new account") }, {'progAccess':(3,), 'shortOption':"i", 'longOption':"image", 'optVal':"IMAGE", 'helpChapter':_("Jabber service options"), 'help':_("set the jpeg image photo for the new account (file)") }, {'progAccess':(3,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Proxy service options"), 'help':_("set the COMMENT field for the new account") }, #{'progAccess':(3,), #'shortOption':"i", #'longOption':"image", #'optVal':"IMAGE", #'helpChapter':_("Unix service options"), #'help':_("set the jpeg image photo for the new account (file)") #}, {'progAccess':(3,), 'shortOption':"d", 'longOption':"home-dir", 'optVal':"HOME_DIR", 'helpChapter':_("Unix service options"), 'help':_("home directory for the new user account") }, {'progAccess':(3,), 'shortOption':"d", 'longOption':"ftp-dir", 'optVal':"FTP_DIR", 'helpChapter':_("FTP service options"), 'help':_("ftp relative directory for the new user account") }, {'progAccess':(3,), 'shortOption':"g", 'longOption':"gid", 'optVal':"GROUP", 'helpChapter':_("Samba service options"), 'help':_("force use GROUP for the new user Unix service account") }, {'progAccess':(3,), 'shortOption':"g", 'longOption':"gid", 'optVal':"GROUP", 'helpChapter':_("FTP service options"), 'help':_("force use GROUP for the new user Unix service account") }, {'progAccess':(3,), 'shortOption':"u", 'longOption':"uid", 'optVal':"UID", 'helpChapter':_("Samba service options"), 'help':_("force use UID for the new user Unix service account") }, {'progAccess':(3,), 'shortOption':"g", 'longOption':"gid", 'optVal':"GROUP", 'helpChapter':_("Mail service options"), 'help':_("force use GROUP for the new user Unix service account") }, {'progAccess':(3,), 'shortOption':"j", 'longOption':"jid", 'optVal':"JID", 'helpChapter':_("Jabber service options"), 'help':_("force use JID for the new user Jabber service account") }, {'progAccess':(3,), 'shortOption':"g", 'longOption':"gid", 'optVal':"GROUP", 'helpChapter':_("Unix service options"), 'help':_("force use GROUP for the new user account") }, {'progAccess':(3,), 'shortOption':"G", 'longOption':"groups", 'optVal':"GROUPS", 'helpChapter':_("Unix service options"), 'help':_("list of supplementary groups for the new user account") }, {'progAccess':(3,), 'shortOption':"G", 'longOption':"groups", 'optVal':"GROUPS", 'helpChapter':_("Samba service options"), 'help':_("list of supplementary groups for the new user account") }, {'progAccess':(3,), 'shortOption':"k", 'longOption':"skel", 'optVal':"SKEL_DIR", 'helpChapter':_("Unix service options"), 'help':_("specify an alternative skel directory") }, {'progAccess':(3,), 'shortOption':"m", 'longOption':"create-home", 'helpChapter':_("Unix service options"), 'help':_("create home directory for the new user account") }, {'progAccess':(3,), 'shortOption':"m", 'longOption':"create-ftp", 'helpChapter':_("FTP service options"), 'help':_("create ftp directory for the new user account") }, {'progAccess':(3,), 'shortOption':"p", 'longOption':"password", 'helpChapter':_("Unix service options"), 'help':_("use password for the user account") +\ " (" + _("from dialog") + ")" }, {'progAccess':(3,), 'shortOption':"P", 'helpChapter':_("Unix service options"), 'help':_("use password for the user account") +\ " (" + _("from standard input") + ")" }, {'progAccess':(3,), 'shortOption':"p", 'longOption':"password", 'helpChapter':_("Proxy service options"), 'help':_("use password for the user account") +\ " (" + _("from dialog") + ")" }, {'progAccess':(3,), 'shortOption':"P", 'helpChapter':_("Proxy service options"), 'help':_("use password for the user account") +\ " (" + _("from standard input") + ")" }, #{'progAccess':(3,), #'shortOption':"f", #'longOption':"force", #'helpChapter':_("Samba service options"), #'help':_("create unix user account and Samba user account") #}, #{'progAccess':(3,), #'shortOption':"f", #'longOption':"force", #'helpChapter':_("Mail service options"), #'help':_("create unix user account and mail user account") #}, {'progAccess':(3,), 'shortOption':"n", 'longOption':"create-profile", 'helpChapter':_("Samba service options"), 'help':_("create a directories for storing new user account \ preferences and data (for users with uid<1000)") }, {'progAccess':(3,), 'shortOption':"p", 'longOption':"password", 'helpChapter':_("Samba service options"), 'help':_("use password for the user account") +\ " (" + _("from dialog") + ")" }, {'progAccess':(3,), 'shortOption':"P", 'helpChapter':_("Samba service options"), 'help':_("use password for the user account") +\ " (" + _("from standard input") + ")" }, {'progAccess':(3,), 'shortOption':"p", 'longOption':"password", 'helpChapter':_("Mail service options"), 'help':_("use password for the user account")+\ " (" + _("from dialog") + ")" }, {'progAccess':(3,), 'shortOption':"P", 'helpChapter':_("Mail service options"), 'help':_("use password for the user account")+\ " (" + _("from standard input") + ")" }, {'progAccess':(3,), 'shortOption':"p", 'longOption':"password", 'helpChapter':_("Jabber service options"), 'help':_("use password for the user account")+\ " (" + _("from dialog") + ")" }, {'progAccess':(3,), 'shortOption':"P", 'helpChapter':_("Jabber service options"), 'help':_("use password for the user account")+\ " (" + _("from standard input") + ")" }, {'progAccess':(3,), 'shortOption':"p", 'longOption':"password", 'helpChapter':_("FTP service options"), 'help':_("use password for the user account")+\ " (" + _("from dialog") + ")" }, {'progAccess':(3,), 'shortOption':"P", 'helpChapter':_("FTP service options"), 'help':_("use password for the user account")+\ " (" + _("from standard input") + ")" }, {'progAccess':(3,), 'shortOption':"w", 'helpChapter':_("Samba service options"), 'help':_("set the trust account")+\ " (" + _("Windows Workstations") + ")" }, {'progAccess':(3,), 'shortOption':"s", 'longOption':"shell", 'optVal':"SHELL", 'helpChapter':_("Unix service options"), 'help':_("the login shell for the new user account") }, {'progAccess':(3,), 'shortOption':"u", 'longOption':"uid", 'optVal':"UID", 'helpChapter':_("Unix service options"), 'help':_("force use the UID for the new user account") }, {'progAccess':(3,), 'shortOption':"v", 'longOption':"visible", 'helpChapter':_("Unix service options"), 'help':_("the new user account is visible (default - invisible)") }, {'progAccess':(4,), 'shortOption':"r", 'longOption':"remove", 'helpChapter':_("Unix service options"), 'help':_("not create backup deleted user data") }, {'progAccess':(4,), 'shortOption':"r", 'longOption':"remove", 'helpChapter':_("Samba service options"), 'help':_("not create backup deleted user data") }, {'progAccess':(4,), 'shortOption':"r", 'longOption':"remove", 'helpChapter':_("Mail service options"), 'help':_("not create backup deleted user data") }, {'progAccess':(5,), 'shortOption':"G", 'longOption':"groups", 'optVal':"GROUPS", 'helpChapter':_("Samba service options"), 'help':_("new list of supplementary GROUPS") }, {'progAccess':(5,), 'shortOption':"s", 'longOption':"smb", 'helpChapter':_("Samba service options"), 'help':_("used in conjunction with the option '-p', \ the password will be changed only for Samba account") }, {'progAccess':(5,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Unix service options"), 'help':_("new value of the COMMENT field") }, {'progAccess':(5,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Samba service options"), 'help':_("new value of the COMMENT field") }, {'progAccess':(5,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Mail service options"), 'help':_("new value of the COMMENT field") }, {'progAccess':(5,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Jabber service options"), 'help':_("new value of the COMMENT field (full name user)") }, {'progAccess':(5,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("FTP service options"), 'help':_("new value of the COMMENT field (full name user)") }, {'progAccess':(5,), 'shortOption':"e", 'longOption':"alt-emails", 'optVal':"ALT_EMAILS", 'helpChapter':_("Mail service options"), 'help':_("set alternate email addresses for the mail account") }, {'progAccess':(5,), 'shortOption':"d", 'longOption':"home", 'optVal':"HOME_DIR", 'helpChapter':_("Unix service options"), 'help':_("new home directory for the user account") }, {'progAccess':(5,), 'shortOption':"g", 'longOption':"gid", 'optVal':"GROUP", 'helpChapter':_("Unix service options"), 'help':_("force use GROUP as new primary group") }, {'progAccess':(5,), 'shortOption':"g", 'longOption':"gid", 'optVal':"GROUP", 'helpChapter':_("Samba service options"), 'help':_("force use GROUP as new primary group") }, {'progAccess':(5,), 'shortOption':"g", 'longOption':"group", 'optVal':"GROUP", 'helpChapter':_("Jabber service options"), 'help':_("force use GROUP for the user Jabber service account") }, {'progAccess':(5,), 'shortOption':"j", 'longOption':"jid", 'optVal':"JID", 'helpChapter':_("Jabber service options"), 'help':_("force use JID for the user Jabber service account") }, {'progAccess':(5,), 'shortOption':"G", 'longOption':"groups", 'optVal':"GROUPS", 'helpChapter':_("Unix service options"), 'help':_("new list of supplementary GROUPS") }, {'progAccess':(5,), 'shortOption':"i", 'longOption':"image", 'optVal':"IMAGE", 'helpChapter':_("Jabber service options"), 'help':_("set the jpeg image photo for user (file)") }, {'progAccess':(5,), 'shortOption':"G", 'longOption':"groups", 'optVal':"GROUPS", 'helpChapter':_("Mail service options"), 'help':_("new list of supplementary email GROUPS") }, {'progAccess':(5,), 'shortOption':"a", 'longOption':"append", 'optVal':"GROUPS", 'helpChapter':_("Unix service options"), 'help':_("append the user to the supplemental GROUPS") }, {'progAccess':(5,), 'shortOption':"a", 'longOption':"append", 'optVal':"GROUPS", 'helpChapter':_("Mail service options"), 'help':_("append the user to the supplemental email GROUPS") }, {'progAccess':(5,), 'shortOption':"m", 'longOption':"move-home", 'helpChapter':_("Unix service options"), 'help':_("move contents of the home directory to the new location")+\ " (" + _("use only with") + " -d)" }, {'progAccess':(5,), 'shortOption':"p", 'longOption':"password", 'helpChapter':_("Common options"), 'help':_("new password for the user account")+\ " (" + _("from dialog") + ")" }, {'progAccess':(5,), 'shortOption':"P", 'helpChapter':_("Common options"), 'help':_("new password for the user account")+\ " (" + _("from standard input") + ")" }, {'progAccess':(5,), 'shortOption':"s", 'longOption':"shell", 'optVal':"SHELL", 'helpChapter':_("Unix service options"), 'help':_("new login shell for the user account") }, {'progAccess':(5,), 'shortOption':"L", 'longOption':"lock", 'helpChapter':_("Unix service options"), 'help':_("lock the user account") }, {'progAccess':(5,), 'shortOption':"U", 'longOption':"unlock", 'helpChapter':_("Unix service options"), 'help':_("unlock the user account") }, {'progAccess':(5,), 'shortOption':"L", 'longOption':"lock", 'helpChapter':_("Samba service options"), 'help':_("lock the user account") }, {'progAccess':(5,), 'shortOption':"U", 'longOption':"unlock", 'helpChapter':_("Samba service options"), 'help':_("unlock the user account") }, {'progAccess':(5,), 'shortOption':"L", 'longOption':"lock", 'helpChapter':_("Mail service options"), 'help':_("lock the user account") }, {'progAccess':(5,), 'shortOption':"U", 'longOption':"unlock", 'helpChapter':_("Mail service options"), 'help':_("unlock the user account") }, {'progAccess':(5,), 'shortOption':"L", 'longOption':"lock", 'helpChapter':_("Jabber service options"), 'help':_("lock the user account") }, {'progAccess':(5,), 'shortOption':"U", 'longOption':"unlock", 'helpChapter':_("Jabber service options"), 'help':_("unlock the user account") }, {'progAccess':(5,), 'shortOption':"V", 'longOption':"visible", 'helpChapter':_("Unix service options"), 'help':_("the user account is visible") }, {'progAccess':(5,), 'shortOption':"I", 'longOption':"invisible", 'helpChapter':_("Unix service options"), 'help':_("the user account is invisible") }, {'progAccess':(5,), 'shortOption':"c", 'longOption':"comment", 'optVal':"COMMENT", 'helpChapter':_("Proxy service options"), 'help':_("new value of the COMMENT field (full name user)") }, {'progAccess':(5,), 'shortOption':"a", 'longOption':"append", 'optVal':"GROUPS", 'helpChapter':_("Proxy service options"), 'help':_("append the user to the supplemental GROUPS") }, {'progAccess':(5,), 'shortOption':"G", 'longOption':"groups", 'optVal':"GROUPS", 'helpChapter':_("Proxy service options"), 'help':_("new list of supplementary GROUPS") }, {'progAccess':(5,), 'shortOption':"L", 'longOption':"lock", 'helpChapter':_("Proxy service options"), 'help':_("lock the user account") }, {'progAccess':(5,), 'shortOption':"U", 'longOption':"unlock", 'helpChapter':_("Proxy service options"), 'help':_("unlock the user account") }, #{'progAccess':(5,), #'shortOption':"u", #'longOption':"uid", #'optVal':"UID", #'helpChapter':_("Common options"), #'help':_("new UID for the user account") #}, {'progAccess':(6,), 'shortOption':"a", 'longOption':"allow", 'helpChapter':_("Samba service options"), 'help':_("enter the allowed ip addresses and network") }, {'progAccess':(6,), 'shortOption':"a", 'longOption':"allow", 'helpChapter':_("Proxy service options"), 'help':_("enter the allowed ip addresses and network") }, {'progAccess':(6,), 'shortOption':"a", 'longOption':"allow", 'helpChapter':_("DNS service options"), 'help':_("enter the allowed ip addresses and network") }, {'progAccess':(6,), 'shortOption':"p", 'longOption':"port", 'optVal':"PORT", 'helpChapter':_("Proxy service options"), 'help':_("port from service Proxy (default 8080)") }, {'progAccess':(6,), 'shortOption':"f", 'longOption':"force", 'helpChapter':_("LDAP service options"), 'help':_("forced setup service") }, {'progAccess':(6,), 'shortOption':"f", 'longOption':"force", 'helpChapter':_("DNS service options"), 'help':_("forced setup service") }, {'progAccess':(6,), 'shortOption':"f", 'longOption':"force", 'helpChapter':_("DHCP service options"), 'help':_("forced setup service") }, {'progAccess':(6,), 'longOption':"net", 'optVal':"NET", 'helpChapter':_("DHCP service options"), 'help':_('network\nexample: --net 192.168.0.0/24') }, {'progAccess':(6,), 'longOption':"router", 'optVal':"ROUTER", 'helpChapter':_("DHCP service options"), 'help':_('router ip\nexample: --router 192.168.0.1') }, {'progAccess':(6,), 'longOption':"dnames", 'optVal':"DNAMES", 'helpChapter':_("DHCP service options"), 'help':_('domain names\nexample: --dnames domain.ru') }, {'progAccess':(6,), 'longOption':"dnsip", 'optVal':"DNSIP", 'helpChapter':_("DHCP service options"), 'help':_('ip domain names servers\n\ example: --dnsip 192.168.0.1,10.0.0.1') }, {'progAccess':(6,), 'longOption':"range", 'optVal':"RANGE", 'helpChapter':_("DHCP service options"), 'help':_('range dynamic ip\n\ example: --range 192.168.0.2,192.168.0.50') }, {'progAccess':(6,), 'shortOption':"n", 'longOption':"netbios", 'optVal':"NETBIOS_NAME", 'helpChapter':_("Samba service options"), 'help':_("netbios name, default hostname") }, {'progAccess':(6,), 'shortOption':"w", 'optVal':"WORKGROUP", 'longOption':"workgroup", 'helpChapter':_("Samba service options"), 'help':_("workgroup, default 'Calculate'") }, {'progAccess':(6,), 'shortOption':"a", 'longOption':"allow", 'helpChapter':_("Mail service options"), 'help':_("enter the allowed ip addresses and network") }, {'progAccess':(6,), 'optVal':"HOST", 'longOption':"host", 'helpChapter':_("Mail service options"), 'help':_("mail host, default - hostname") }, {'progAccess':(6,), 'shortOption':"t", 'optVal':"TYPE", 'longOption':"type", 'helpChapter':_("Mail service options"), 'help':_("mail type - 'imap', 'pop3', 'pop3,imap' (default - imap)") }, {'progAccess':(6,), 'shortOption':"c", 'optVal':"CRYPT", 'longOption':"crypt", 'helpChapter':_("Mail service options"), 'help':_("encryption type - 'none', 'tls' (default - tls)") }, {'progAccess':(6,), 'optVal':"HOST", 'longOption':"host", 'helpChapter':_("Jabber service options"), 'help':_("jabber host, default - hostname") }, {'progAccess':(6,), 'optVal':"HOSTS", 'longOption':"hosts", 'helpChapter':_("Jabber service options"), 'help':_("jabber supplementary hosts, (comma delimited)") }, # Опции cl-passwd # LDAP пользователь {'progAccess':(7,), 'shortOption':"d", 'longOption':"delete", 'helpChapter':_("Unix service options"), 'help':_("delete the password for the named account") }, {'progAccess':(7,), 'shortOption':"s", 'longOption':"smb", 'helpChapter':_("Samba service options"), 'help':_("password will be changed only for Samba account") }, {'progAccess':(7,), 'shortOption':"l", 'longOption':"lock", 'helpChapter':_("Unix service options"), 'help':_("lock the user account") }, {'progAccess':(7,), 'shortOption':"u", 'longOption':"unlock", 'helpChapter':_("Unix service options"), 'help':_("unlock the user account") }, {'progAccess':(7,), 'shortOption':"l", 'longOption':"lock", 'helpChapter':_("Samba service options"), 'help':_("lock the user account") }, {'progAccess':(7,), 'shortOption':"u", 'longOption':"unlock", 'helpChapter':_("Samba service options"), 'help':_("unlock the user account") }, {'progAccess':(7,), 'shortOption':"l", 'longOption':"lock", 'helpChapter':_("Mail service options"), 'help':_("lock the user account") }, {'progAccess':(7,), 'shortOption':"u", 'longOption':"unlock", 'helpChapter':_("Mail service options"), 'help':_("unlock the user account") }, {'progAccess':(7,), 'shortOption':"l", 'longOption':"lock", 'helpChapter':_("Jabber service options"), 'help':_("lock the user account") }, {'progAccess':(7,), 'shortOption':"u", 'longOption':"unlock", 'helpChapter':_("Jabber service options"), 'help':_("unlock the user account") }, {'progAccess':(7,), 'shortOption':"l", 'longOption':"lock", 'helpChapter':_("Proxy service options"), 'help':_("lock the user account") }, {'progAccess':(7,), 'shortOption':"u", 'longOption':"unlock", 'helpChapter':_("Proxy service options"), 'help':_("unlock the user account") }, {'progAccess':(8,), 'shortOption':"b", 'longOption':"backup", 'helpChapter':_("Common options"), 'help':_("backup services configuration files and LDAP branches")+\ " (" + _("default option") + ")" }, {'progAccess':(8,), 'shortOption':"r", 'longOption':"restore", 'helpChapter':_("Common options"), 'help':_("restore services configuration files and LDAP branches") }, {'progAccess':(9,), 'optVal':"HOST", 'longOption':"host", 'helpChapter':_("Jabber service options"), 'help':_("jabber host, default - hostname") }, {'progAccess':(9,), 'optVal':"HOSTS", 'longOption':"hosts", 'helpChapter':_("Jabber service options"), 'help':_("jabber supplementary hosts, (comma delimited)") }, {'progAccess':(9,), 'shortOption':"a", 'longOption':"allow", 'helpChapter':_("Mail service options"), 'help':_("enter the allowed ip addresses and network") }, {'progAccess':(9,), 'shortOption':"t", 'optVal':"TYPE", 'longOption':"type", 'helpChapter':_("Mail service options"), 'help':_("mail type - 'imap', 'pop3', 'pop3,imap'") }, {'progAccess':(9,), 'shortOption':"c", 'optVal':"CRYPT", 'longOption':"crypt", 'helpChapter':_("Mail service options"), 'help':_("encryption type - 'none', 'tls'") }, {'progAccess':(9,), 'shortOption':"a", 'longOption':"allow", 'helpChapter':_("Samba service options"), 'help':_("enter the allowed ip addresses and network") }, {'progAccess':(9,), 'shortOption':"a", 'longOption':"allow", 'helpChapter':_("Proxy service options"), 'help':_("enter the allowed ip addresses and network") }, {'progAccess':(6,9), 'optVal':"CONDITION", 'longOption':"history", 'helpChapter':_("Mail service options"), 'help':_("enabled or disabled mail history logging, default disable.\ (on/off)") }, {'progAccess':(6,9), 'optVal':"DOMAIN", 'longOption':"history-domains", 'helpChapter':_("Mail service options"), 'help':_("domain or domains for own mail (comma delimited)") }, {'progAccess':(6,9), 'optVal':"PATH", 'longOption':"history-path", 'helpChapter':_("Mail service options"), 'help':_("history path") }, {'progAccess':(6,), 'optVal':"HOST", 'longOption':"host", 'helpChapter':_("Proxy service options"), 'help':_("proxy host, default - hostname") }, {'progAccess':(9,), 'shortOption':"p", 'longOption':"port", 'optVal':"PORT", 'helpChapter':_("Proxy service options"), 'help':_("port from service Proxy") }, {'progAccess':(9,), 'optVal':"HOST", 'longOption':"host", 'helpChapter':_("Proxy service options"), 'help':_("proxy host, default - hostname") }, {'progAccess':(10,), 'shortOption':"a", 'longOption':"allow", 'helpChapter':_("Common options"), 'help':_("enter the allowed ip addresses and network\ for installed services") }, {'progAccess':(9,10), 'shortOption':"v", 'longOption':"verbose", 'helpChapter':_("Common options"), 'help':_("display additional information") }, {'progAccess':(10,), 'longOption':"repl", 'helpChapter':_("Common options"), 'help':_("using the backup of another server,\ replicate runs on the server") }, {'progAccess':(11,), 'optVal':"LOGIN", 'longOption':"login", 'helpChapter':_("Common options"), 'help':_("user name for login to the server") }, {'progAccess':(11,), 'optVal':"LOGOUT", 'longOption':"logout", 'helpChapter':_("Common options"), 'help':_("user name to logout from the server") }, {'progAccess':(11,), 'optVal':"MAKEDIR", 'longOption':"makedir", 'helpChapter':_("Common options"), 'help':_("user name to create user directories on the server") }, {'progAccess':(11,), 'shortOption':"s", 'longOption':"silent", 'helpChapter':_("Common options"), 'help':_("silent mode messages") }, {'progAccess':(12,), 'shortOption':"r", 'optVal':"R_HOSTS", 'longOption':"rhosts", 'helpChapter':_("Common options"), 'help':_("servers replication (comma delimited)") }, {'progAccess':(12,), 'longOption':"off", 'helpChapter':_("Common options"), 'help':_("replication off") }, {'progAccess':(14,), 'shortOption':"m", 'longOption':"machines", 'helpChapter':_("Samba service options"), 'help':_("information about all machines") }, {'progAccess':(14,), 'shortOption':"M", 'optVal':"MACHINE", 'helpChapter':_("Samba service options"), 'help':_("information about the machine") }, {'progAccess':(14,), 'shortOption':"u", 'longOption':"users", 'helpChapter':_("Unix service options"), 'help':_("information about all users") }, {'progAccess':(14,), 'shortOption':"U", 'optVal':"LOGIN", 'helpChapter':_("Unix service options"), 'help':_("information about the user") }, {'progAccess':(14,), 'longOption':"full", 'helpChapter':_("Unix service options"), 'help':_("full information (all fields)") }, {'progAccess':(14,), 'shortOption':"u", 'longOption':"users", 'helpChapter':_("Samba service options"), 'help':_("information about all users") }, {'progAccess':(14,), 'shortOption':"U", 'optVal':"LOGIN", 'helpChapter':_("Samba service options"), 'help':_("information about the user") }, {'progAccess':(14,), 'longOption':"full", 'helpChapter':_("Samba service options"), 'help':_("full information (all fields)") }, {'progAccess':(14,), 'shortOption':"u", 'longOption':"users", 'helpChapter':_("Mail service options"), 'help':_("information about all users") }, {'progAccess':(14,), 'shortOption':"U", 'optVal':"LOGIN", 'helpChapter':_("Mail service options"), 'help':_("information about the user") }, {'progAccess':(14,), 'longOption':"full", 'helpChapter':_("Mail service options"), 'help':_("full information (all fields)") }, {'progAccess':(14,), 'shortOption':"u", 'longOption':"users", 'helpChapter':_("Jabber service options"), 'help':_("information about all users") }, {'progAccess':(14,), 'shortOption':"U", 'optVal':"LOGIN", 'helpChapter':_("Jabber service options"), 'help':_("information about the user") }, {'progAccess':(14,), 'longOption':"full", 'helpChapter':_("Jabber service options"), 'help':_("full information (all fields)") }, {'progAccess':(14,), 'shortOption':"u", 'longOption':"users", 'helpChapter':_("FTP service options"), 'help':_("information about all users") }, {'progAccess':(14,), 'shortOption':"U", 'optVal':"LOGIN", 'helpChapter':_("FTP service options"), 'help':_("information about the user") }, {'progAccess':(14,), 'longOption':"full", 'helpChapter':_("FTP service options"), 'help':_("full information (all fields)") }, {'progAccess':(14,), 'shortOption':"u", 'longOption':"users", 'helpChapter':_("Proxy service options"), 'help':_("information about all users") }, {'progAccess':(14,), 'shortOption':"U", 'optVal':"LOGIN", 'helpChapter':_("Proxy service options"), 'help':_("information about the user") }, {'progAccess':(14,), 'longOption':"full", 'helpChapter':_("Proxy service options"), 'help':_("full information (all fields)") }, {'progAccess':(14,), 'shortOption':"g", 'longOption':"groups", 'helpChapter':_("Unix service options"), 'help':_("information about all groups") }, {'progAccess':(14,), 'shortOption':"G", 'optVal':"GROUP", 'helpChapter':_("Unix service options"), 'help':_("information about the group") }, {'progAccess':(14,), 'shortOption':"g", 'longOption':"groups", 'helpChapter':_("Samba service options"), 'help':_("information about all groups") }, {'progAccess':(14,), 'shortOption':"G", 'optVal':"GROUP", 'helpChapter':_("Samba service options"), 'help':_("information about the group") }, {'progAccess':(14,), 'shortOption':"g", 'longOption':"groups", 'helpChapter':_("Mail service options"), 'help':_("information about all groups") }, {'progAccess':(14,), 'shortOption':"G", 'optVal':"GROUP", 'helpChapter':_("Mail service options"), 'help':_("information about the group") }, {'progAccess':(14,), 'shortOption':"g", 'longOption':"groups", 'helpChapter':_("Jabber service options"), 'help':_("information about all groups") }, {'progAccess':(14,), 'shortOption':"G", 'optVal':"GROUP", 'helpChapter':_("Jabber service options"), 'help':_("information about the group") }, {'progAccess':(14,), 'shortOption':"g", 'longOption':"groups", 'helpChapter':_("Proxy service options"), 'help':_("information about all groups") }, {'progAccess':(14,), 'shortOption':"G", 'optVal':"GROUP", 'helpChapter':_("Proxy service options"), 'help':_("information about the group") }, {'progAccess':(14,), 'shortOption':"z", 'helpChapter':_("DNS service options"), 'help':_("information about the all DNS zones") }, {'progAccess':(14,), 'shortOption':"Z", 'optVal':"ZONE", 'helpChapter':_("DNS service options"), 'help':_("information about the DNS zone ('zone name' for \ forward zone, 'net name' for reverse zone)") }, {'progAccess':(14,), 'shortOption':"r", 'optVal':"RECORD", 'helpChapter':_("DNS service options"), 'help':_("information about the DNS record ('host name' for \ forward zone, 'host ip' for reverse zone)") }, {'progAccess':(14,), 'shortOption':"n", 'helpChapter':_("DHCP service options"), 'help':_("information about the all DHCP networks") }, {'progAccess':(14,), 'shortOption':"N", 'optVal':"NETWORK", 'helpChapter':_("DHCP service options"), 'help':_("information about the DHCP network") }, {'progAccess':(14,), 'longOption':"hosts", 'helpChapter':_("DHCP service options"), 'help':_("information about the all DHCP static hosts") }, {'progAccess':(14,), 'shortOption':"H", 'optVal':"HOST", 'helpChapter':_("DHCP service options"), 'help':_("information about the DHCP static host") }, {'progAccess':(15,), 'shortOption':"s", 'optVal':"PROXY_DN", 'helpChapter':_("Common options"), 'help':_("distinguished name (dn) - service Proxy") }, {'progAccess':(15,), 'shortOption':"b", 'optVal':"BASE_DN", 'helpChapter':_("Common options"), 'help':_("base distinguished name (dn)") }, {'progAccess':(15,), 'shortOption':"p", 'optVal':"PROXY_PW", 'helpChapter':_("Common options"), 'help':_("password for distinguished name (dn) - service Proxy") }, {'progAccess':(15,), 'shortOption':"P", 'optVal':"FILE_PW", 'helpChapter':_("Common options"), 'help':_("password for distinguished name (dn) - service Proxy from \ file") }, {'progAccess':(16,), 'longOption':"autoptr", 'optVal':"CONDITION", 'helpChapter':_("Common options"), 'help':_("When create a A-record will be automatically created \ PTR-record (on/off, on - default)") }, {'progAccess':(16,), 'shortOption':"t", 'longOption':"type", 'optVal':"TYPE", 'helpChapter':_("Common options"), 'help':_("type record 'a' - forward record (default), 'ptr' - reverse \ record, 'cname' - canonical name record") }, {'progAccess':(16,), 'longOption':"host", 'optVal':"HOST", 'helpChapter':_("Common options"), 'help':_("fully qualified host name (includes host name and domain \ name)") }, {'progAccess':(16,), 'longOption':"cname", 'optVal':"CNAME", 'helpChapter':_("Common options"), 'help':_("canonical name (fully qualified host name) for CNAME-record") }, {'progAccess':(16,), 'longOption':"ip", 'optVal':"IP_ADDRESS", 'helpChapter':_("Common options"), 'help':_("ip address") }, {'progAccess':(16,), 'longOption':"mx", 'optVal':"MAIL_SERVERS", 'helpChapter':_("Common options"), 'help':_("host names mail servers for mail exchanger (comma \ delimited)") }, {'progAccess':(16,), 'shortOption':"f", 'longOption':"force", 'helpChapter':_("Common options"), 'help':_("disable the check of dhcp config") }, {'progAccess':(17,), 'longOption':"host", 'optVal':"HOST", 'helpChapter':_("Common options"), 'help':_("fully qualified host name (includes host name and domain \ name), delete forward record") }, {'progAccess':(17,), 'longOption':"ip", 'optVal':"IP_ADDRESS", 'helpChapter':_("Common options"), 'help':_("ip address, delete reverse record") }, {'progAccess':(17,), 'longOption':"mx", 'helpChapter':_("Common options"), 'help':_("remove all MX-records from an existing A-record \ (used with option --host)") }, {'progAccess':(18,), 'longOption':"automod", 'optVal':"CONDITION", 'helpChapter':_("Common options"), 'help':_("When modify a A-record will be automatically modified \ PTR-record or when modify a PTR-record will be automatically modified \ A-record (on/off, on - default)") }, {'progAccess':(18,), 'shortOption':"t", 'longOption':"type", 'optVal':"TYPE", 'helpChapter':_("Common options"), 'help':_("type record 'a' - forward record (default), 'ptr' - reverse \ record, 'cname' - canonical name record") }, {'progAccess':(18,), 'longOption':"host", 'optVal':"HOST", 'helpChapter':_("Common options"), 'help':_("new fully qualified host name (includes host name and \ domain name)") }, {'progAccess':(18,), 'longOption':"ip", 'optVal':"IP", 'helpChapter':_("Common options"), 'help':_("new ip address") }, {'progAccess':(18,), 'longOption':"mx", 'optVal':"MAIL_SERVERS", 'helpChapter':_("Common options"), 'help':_("new hostnames mail servers for mail exchanger (comma \ delimited)") }, {'progAccess':(18,), 'longOption':"mxmod", 'optVal':"MAIL_SERVERS", 'helpChapter':_("Common options"), 'help':_("rename old hostname mail server to new hostname mail server \ for mail exchanger (comma delimited)") }, {'progAccess':(18,), 'longOption':"cname", 'optVal':"CNAME", 'helpChapter':_("Common options"), 'help':_("new canonical name (CNAME-record)") }, {'progAccess':(18,), 'shortOption':"f", 'longOption':"force", 'helpChapter':_("Common options"), 'help':_("disable the check of dhcp config") }, {'progAccess':(19,), 'shortOption':"t", 'longOption':"type", 'optVal':"TYPE", 'helpChapter':_("Common options"), 'help':_("zone type (master/slave)") }, {'progAccess':(19,), 'shortOption':"n", 'longOption':"name", 'optVal':"NAME", 'helpChapter':_("Common options"), 'help':_("zone name, 'domain name' for forward zone or 'net name' for \ reverse zone") }, {'progAccess':(19,), 'longOption':"server", 'optVal':"SERVER", 'helpChapter':_("Common options"), 'help':_("master autoritative DNS server for zone (hostname server)") }, {'progAccess':(19,), 'longOption':"ipserver", 'optVal':"IPSERVER", 'helpChapter':_("Common options"), 'help':_("ip for master autoritative DNS server for zone") }, {'progAccess':(19,), 'longOption':"ip", 'optVal':"IP_ZONE", 'helpChapter':_("Common options"), 'help':_("ip zone") }, {'progAccess':(19,), 'longOption':"email", 'optVal':"email", 'helpChapter':_("Common options"), 'help':_("email administrator zone") }, {'progAccess':(19,), 'longOption':"servers", 'optVal':"SERVERS", 'helpChapter':_("Common options"), 'help':_("All autoritative DNS servers for zone (comma delimited)") }, {'progAccess':(19,), 'longOption':"mx", 'optVal':"MAIL_SERVERS", 'helpChapter':_("Common options"), 'help':_("host names mail servers for mail exchanger (comma \ delimited)") }, {'progAccess':(19,), 'longOption':"refresh", 'optVal':"REFRESH", 'helpChapter':_("Common options"), 'help':_("time interval for updating zone, default - 8H (8 hours)") }, {'progAccess':(19,), 'longOption':"update", 'optVal':"UPDATE", 'helpChapter':_("Common options"), 'help':_("time interval for updating zone after an unsuccessful \ update zone, default - 2H (2 hours)") }, {'progAccess':(19,), 'longOption':"expiry", 'optVal':"EXPIRY", 'helpChapter':_("Common options"), 'help':_("time interval, if during this time interval slave DNS \ server can not update zone, zone is outdated in slave DNS server, \ default - 2W (2 weeks)") }, {'progAccess':(19,), 'longOption':"minimum", 'optVal':"MINIMUM", 'helpChapter':_("Common options"), 'help':_("time interval stored in cache failed DNS queries to the \ zone, default - 2H (2 hours)") }, {'progAccess':(20,), 'shortOption':"n", 'longOption':"name", 'optVal':"NAME", 'helpChapter':_("Common options"), 'help':_("zone name, 'domain name' for forward zone or 'net name' for \ reverse zone") }, {'progAccess':(20,), 'longOption':"ip", 'helpChapter':_("Common options"), 'help':_("remove all A-records from an existing zone \ (used with option --name)") }, {'progAccess':(20,), 'longOption':"mx", 'helpChapter':_("Common options"), 'help':_("remove all MX-records from an existing zone \ (used with option --name)") }, {'progAccess':(21,), 'shortOption':"n", 'longOption':"name", 'optVal':"NAME", 'helpChapter':_("Common options"), 'help':_("zone name, 'domain name' for forward zone or 'net name' for \ reverse zone") }, {'progAccess':(21,), 'longOption':"server", 'optVal':"SERVER", 'helpChapter':_("Common options"), 'help':_("master autoritative DNS server for zone (hostname server)") }, {'progAccess':(21,), 'longOption':"ip", 'optVal':"IP_ZONE", 'helpChapter':_("Common options"), 'help':_("new ip address") }, {'progAccess':(21,), 'longOption':"mx", 'optVal':"MAIL_SERVERS", 'helpChapter':_("Common options"), 'help':_("new hostnames mail servers for mail exchanger (comma \ delimited)") }, {'progAccess':(21,), 'longOption':"mxmod", 'optVal':"MAIL_SERVERS", 'helpChapter':_("Common options"), 'help':_("rename old hostname mail server to new hostname mail server \ for mail exchanger (comma delimited)") }, {'progAccess':(21,), 'longOption':"email", 'optVal':"email", 'helpChapter':_("Common options"), 'help':_("email administrator zone") }, {'progAccess':(21,), 'longOption':"servers", 'optVal':"SERVERS", 'helpChapter':_("Common options"), 'help':_("All autoritative DNS servers for zone (comma delimited)") }, {'progAccess':(21,), 'longOption':"refresh", 'optVal':"REFRESH", 'helpChapter':_("Common options"), 'help':_("time interval for updating zone, default - 8H (8 hours)") }, {'progAccess':(21,), 'longOption':"update", 'optVal':"UPDATE", 'helpChapter':_("Common options"), 'help':_("time interval for updating zone after an unsuccessful \ update zone, default - 2H (2 hours)") }, {'progAccess':(21,), 'longOption':"expiry", 'optVal':"EXPIRY", 'helpChapter':_("Common options"), 'help':_("time interval, if during this time interval slave DNS \ server can not update zone, zone is outdated in slave DNS server, \ default - 2W (2 weeks)") }, {'progAccess':(21,), 'longOption':"minimum", 'optVal':"MINIMUM", 'helpChapter':_("Common options"), 'help':_("time interval stored in cache failed DNS queries to the \ zone, default - 2H (2 hours)") }, {'progAccess':(22,), 'longOption':"net", 'optVal':"NET", 'helpChapter':_("Common options"), 'help':_('network\nexample: --net 192.168.0.0/24') }, {'progAccess':(22,), 'longOption':"router", 'optVal':"ROUTER", 'helpChapter':_("Common options"), 'help':_('router ip\nexample: --router 192.168.0.1') }, {'progAccess':(22,), 'longOption':"dnames", 'optVal':"DNAMES", 'helpChapter':_("Common options"), 'help':_('domain names\nexample: --dnames domain.ru') }, {'progAccess':(22,), 'longOption':"dnsip", 'optVal':"DNSIP", 'helpChapter':_("Common options"), 'help':_('ip domain names servers\n\ example: --dnsip 192.168.0.1,10.0.0.1') }, {'progAccess':(22,), 'longOption':"range", 'optVal':"RANGE", 'helpChapter':_("Common options"), 'help':_('range dynamic ip\n\ example: --range 192.168.0.2,192.168.0.50') }, {'progAccess':(23,), 'longOption':"net", 'optVal':"NET", 'helpChapter':_("Common options"), 'help':_('network\nexample: --net 192.168.0.0/24') }, #{'progAccess':(23,), #'longOption':"dnames", #'helpChapter':_("Common options"), #'help':_('domain names') #}, #{'progAccess':(23,), #'longOption':"dnsip", #'helpChapter':_("Common options"), #'help':_('ip domain names servers') #}, {'progAccess':(24,), 'longOption':"router", 'optVal':"ROUTER", 'helpChapter':_("Common options"), 'help':_('router ip\nexample: --router 192.168.0.1') }, {'progAccess':(24,), 'longOption':"dnames", 'optVal':"DNAMES", 'helpChapter':_("Common options"), 'help':_('domain names\nexample: --dnames domain.ru') }, {'progAccess':(24,), 'longOption':"dnsip", 'optVal':"DNSIP", 'helpChapter':_("Common options"), 'help':_('ip domain names servers\n\ example: --dnsip 192.168.0.1,10.0.0.1') }, {'progAccess':(24,), 'longOption':"range", 'optVal':"RANGE", 'helpChapter':_("Common options"), 'help':_('range dynamic ip\n\ example: --range 192.168.0.2,192.168.0.50') }, {'progAccess':(25,), 'longOption':"host", 'optVal':"HOST", 'helpChapter':_("Common options"), 'help':_('host name\nexample: --host computer') }, {'progAccess':(25,), 'longOption':"ip", 'optVal':"IP", 'helpChapter':_("Common options"), 'help':_('ip address\nexample: --ip 192.168.0.2') }, {'progAccess':(25,), 'longOption':"mac", 'optVal':"MAC", 'helpChapter':_("Common options"), 'help':_('mac address\nexample: --mac 00:1e:8c:66:a4:b1') }, {'progAccess':(26,), 'longOption':"host", 'optVal':"HOST", 'helpChapter':_("Common options"), 'help':_('host name\nexample: --host computer') }, {'progAccess':(27,), 'longOption':"ip", 'optVal':"IP", 'helpChapter':_("Common options"), 'help':_('ip address\nexample: --ip 192.168.0.2') }, {'progAccess':(27,), 'longOption':"mac", 'optVal':"MAC", 'helpChapter':_("Common options"), 'help':_('mac address\nexample: --mac 00:1e:8c:66:a4:b1') }, {'progAccess':(28,), 'longOption':"ip", 'optVal':"IP", 'helpChapter':_("Common options"), 'help':_('ip address\nexample: --ip 192.168.0.2') }, {'progAccess':(28,), 'longOption':"domain", 'optVal':"DOMAIN", 'helpChapter':_("Common options"), 'help':_('domain name\nexample: --domain domain.org') }, {'progAccess':(28,), 'longOption':"host", 'optVal':"HOST", 'helpChapter':_("Common options"), 'help':_('host name\nexample: --host computer') }, {'progAccess':(28,), 'shortOption':"s", 'optVal':"DNS_DN", 'helpChapter':_("Common options"), 'help':_("distinguished name (dn) - service DNS") }, {'progAccess':(28,), 'shortOption':"b", 'optVal':"BASE_DN", 'helpChapter':_("Common options"), 'help':_("base distinguished name (dn)") }, {'progAccess':(28,), 'shortOption':"p", 'optVal':"DNS_PW", 'helpChapter':_("Common options"), 'help':_("password for distinguished name (dn) - service DNS") }, {'progAccess':(28,), 'shortOption':"P", 'optVal':"FILE_PW", 'helpChapter':_("Common options"), 'help':_("password for distinguished name (dn) - service DNS from \ file") }, #{'progAccess':(0,1,2,4,5,6), #'shortOption':"s", #'longOption':"set", #'optVal':"=", #'helpChapter':_("Common options"), #'help':_("change enviroment values") #}, #{'shortOption':"e", #'longOption':"env", #'optVal':"filter", #'helpChapter':_("Common options"), #'help':_("show enviroment values (filter for type, all - no filter)") #}, # Services {'progAccess':(6,), 'helpChapter':_("Services"), 'help':pcs(" ldap", self.column_width, "ldap " + servName, self.consolewidth-self.column_width) }, {'progAccess':(0,1,2,3,4,5,6,7,9,12,14), 'helpChapter':_("Services"), 'help':pcs(" unix", self.column_width, "unix " + servName, self.consolewidth-self.column_width) }, {'progAccess':(0,1,2,3,4,5,6,7,9,12,14), 'helpChapter':_("Services"), 'help':pcs(" samba", self.column_width, "samba " + servName, self.consolewidth-self.column_width) }, {'progAccess':(0,1,2,3,4,5,6,7,9,12,14), 'helpChapter':_("Services"), 'help':pcs(" mail", self.column_width, "mail " + servName, self.consolewidth-self.column_width) }, {'progAccess':(0,1,2,3,4,5,6,7,9,14), 'helpChapter':_("Services"), 'help':pcs(" jabber", self.column_width, "jabber " + servName, self.consolewidth-self.column_width) }, {'progAccess':(3,4,5,6,7,9,14), 'helpChapter':_("Services"), 'help':pcs(" ftp", self.column_width, "ftp " + servName, self.consolewidth-self.column_width) }, {'progAccess':(0,1,2,3,4,5,6,7,9,14), 'helpChapter':_("Services"), 'help':pcs(" proxy", self.column_width, "proxy " + servName, self.consolewidth-self.column_width) }, {'progAccess':(6,9,14), 'helpChapter':_("Services"), 'help':pcs(" dns", self.column_width, "dns " + servName, self.consolewidth-self.column_width) }, {'progAccess':(6,9,14), 'helpChapter':_("Services"), 'help':pcs(" dhcp", self.column_width, "dhcp " + servName, self.consolewidth-self.column_width) }, ##{'helpChapter':_("Services"), ##'help':" mail \t\t\tmail " + servName + "\n" ##}, ##{'helpChapter':_("Services"), ##'help':" ftp \t\t\tftp " + servName + "\n" ##}, ##{'helpChapter':_("Services"), ##'help':" proxy \t\tproxy " + servName + "\n" ##}, ##{'helpChapter':_("Services"), ##'help':" radius \t\tradius " + servName + "\n" ##}, ##{'helpChapter':_("Services"), ##'help':" jabber \t\tjabber " + servName + "\n" ##}, ##{'helpChapter':_("Services"), ##'help':" addressbook \t\taddressbook " + servName + "\n" ##}, ##{'helpChapter':_("Services"), ##'help':" dhcp \t\t\tdhcp " + servName + "\n" ##}, ##{'helpChapter':_("Services"), ##'help':" named \t\tnamed " + servName + "\n" ##}, ##{'helpChapter':_("Services"), ##'help':" wiki \t\t\twiki " + servName + "\n" ##}, # Informative output { #'progAccess':(3,), 'helpChapter':"Copyright", 'help':Version }, # Использование { 'progAccess':(1,), 'helpChapter':_("Usage"), 'help': cmdName + " " +_("group") + " " + _("service") }, { 'progAccess':(0,2), 'helpChapter':_("Usage"), 'help': cmdName + " [" + _("options") + "] " +\ _("group") + " " + _("service") }, { 'progAccess':(3,4,5,7), 'helpChapter':_("Usage"), 'help': cmdName + " [" + _("options") + "] " + _("user") +\ " " + _("service") }, { 'progAccess':(6,12,14), 'helpChapter':_("Usage"), 'help': cmdName + " [" + _("options") + "] "+\ " " + _("service") }, { 'progAccess':(8,11,15,16,17,19,20,21,22,23,25,26,28), 'helpChapter':_("Usage"), 'help': cmdName + " [" + _("options") + "]" }, { 'progAccess':(9,), 'helpChapter':_("Usage"), 'help': cmdName + " " + _("service") }, { 'progAccess':(10,13), 'helpChapter':_("Usage"), 'help': cmdName }, { 'progAccess':(18,), 'helpChapter':_("Usage"), 'help': cmdName + " [" + _("options") + "]" + " <" +\ _("hostname or ip") + ">" }, { 'progAccess':(24,), 'helpChapter':_("Usage"), 'help': cmdName + " [" + _("options") + "]" + " " +_("network") }, { 'progAccess':(27,), 'helpChapter':_("Usage"), 'help': cmdName + " [" + _("options") + "]" + " " +_("hostname") }, # Function { 'progAccess':(0,), 'helpChapter':"Function", 'help':_("Add group in LDAP directory service") }, { 'progAccess':(1,), 'helpChapter':"Function", 'help':_("Delete group from LDAP directory service") }, { 'progAccess':(2,), 'helpChapter':"Function", 'help':_("Modify group profiles in LDAP directory service") }, { 'progAccess':(3,), 'helpChapter':"Function", 'help':_("Add user in LDAP directory service") }, { 'progAccess':(4,), 'helpChapter':"Function", 'help':_("Delete user from LDAP directory service") }, { 'progAccess':(5,), 'helpChapter':"Function", 'help':_("Modify user profiles in LDAP directory service") }, { 'progAccess':(6,), 'helpChapter':"Function", 'help':_("Sets service in the system") }, { 'progAccess':(7,), 'helpChapter':"Function", 'help':_("Change user password") }, { 'progAccess':(8,), 'helpChapter':"Function", 'help':_("Backup or restore installed services") }, { 'progAccess':(9,), 'helpChapter':"Function", 'help':_("Updates configuration files for the service") }, { 'progAccess':(10,), 'helpChapter':"Function", 'help':_("Rebuild configuration files and LDAP database for all \ services") }, { 'progAccess':(11,), 'helpChapter':"Function", 'help':_("Runs the actions on the server when mounting and \ unmounting of user resources.") }, { 'progAccess':(12,), 'helpChapter':"Function", 'help':_("Setup and configure replication between LDAP servers") }, { 'progAccess':(13,), 'helpChapter':"Function", 'help':_("Deletes the users directories, which had been previously \ removed from the LDAP using replication") }, { 'progAccess':(14,), 'helpChapter':"Function", 'help':_("Information about all services") }, { 'progAccess':(15,), 'helpChapter':"Function", 'help':_("Checks the users access to the Internet using a Proxy \ service") }, { 'progAccess':(16,), 'helpChapter':"Function", 'help':_("Add DNS record in LDAP") }, { 'progAccess':(17,), 'helpChapter':"Function", 'help':_("Delete DNS record in LDAP") }, { 'progAccess':(18,), 'helpChapter':"Function", 'help':_("Modify DNS record in LDAP") }, { 'progAccess':(19,), 'helpChapter':"Function", 'help':_("Add DNS zone") }, { 'progAccess':(20,), 'helpChapter':"Function", 'help':_("Delete DNS zone") }, { 'progAccess':(21,), 'helpChapter':"Function", 'help':_("Modify DNS zone") }, { 'progAccess':(22,), 'helpChapter':"Function", 'help':_("Add DHCP network") }, { 'progAccess':(23,), 'helpChapter':"Function", 'help':_("Delete DHCP network") }, { 'progAccess':(24,), 'helpChapter':"Function", 'help':_("Modify DHCP network") }, { 'progAccess':(25,), 'helpChapter':"Function", 'help':_("Add DHCP static host") }, { 'progAccess':(26,), 'helpChapter':"Function", 'help':_("Delete DHCP static host") }, { 'progAccess':(27,), 'helpChapter':"Function", 'help':_("Modify DHCP static host") }, { 'progAccess':(28,), 'helpChapter':"Function", 'help':_("Add DHCP service host in DNS service") }, # Примеры { 'progAccess':(0,), 'helpChapter':_("Examples"), 'help':pcs( " cl-groupadd guest ldap", self.column_width, "# " + _("add group guest in LDAP service"), self.consolewidth-self.column_width ) }, { 'progAccess':(1,), 'helpChapter':_("Examples"), 'help':pcs( " cl-groupdel guest unix", self.column_width, "# " + _("delete group guest from Unix service") + "." , self.consolewidth-self.column_width) }, { 'progAccess':(2,), 'helpChapter':_("Examples"), 'help':pcs( " cl-groupmod -a guest test unix", self.column_width, "# " + _("add user test to group guest in Unix service"), self.consolewidth-self.column_width ) }, { 'progAccess':(3,), 'helpChapter':_("Examples"), 'help':pcs(" cl-useradd guest samba", self.column_width, "# " +_("add user guest in Samba service") + ".", self.consolewidth - self.column_width) }, { 'progAccess':(4,), 'helpChapter':_("Examples"), 'help':pcs(" cl-userdel guest samba", self.column_width, "# " + _("delete user guest from Samba service") + ".", self.consolewidth-self.column_width) }, { 'progAccess':(5,), 'helpChapter':_("Examples"), 'help':pcs(" cl-usermod -a test guest unix", self.column_width, "# " + _("append user guest to the supplemental group test") +\ ".", self.consolewidth-self.column_width) }, { 'progAccess':(6,), 'helpChapter':_("Examples"), 'help':pcs(" cl-setup samba", self.column_width, "# "+_("set Samba service in the system") + ".", self.consolewidth-self.column_width) }, { 'progAccess':(7,), 'helpChapter':_("Examples"), 'help':pcs(" cl-passwd test samba", self.column_width, "# "+_("change password of user test for Samba service") + ".", self.consolewidth-self.column_width) }, { 'progAccess':(8,), 'helpChapter':_("Examples"), 'help':pcs(" cl-backup-server -r", self.column_width, "# "+_("restore all services") + ".", self.consolewidth-self.column_width) }, { 'progAccess':(9,), 'helpChapter':_("Examples"), 'help':pcs(" cl-update-server samba", self.column_width, "# "+_("update config files Samba services") + ".", self.consolewidth-self.column_width) }, { 'progAccess':(10,), 'helpChapter':_("Examples"), 'help':pcs(" cl-rebuild", self.column_width, "# "+_("rebuild all services") + ".", self.consolewidth-self.column_width) }, { 'progAccess':(11,), 'helpChapter':_("Examples"), 'help':pcs(" execserv --login test", self.column_width, "# "+_("runs the necessary actions on the server for the user \ 'test' when mounting its resources") + ".", self.consolewidth-self.column_width) }, #{ #'helpChapter':_("Examples"), #'help':pcs(" " + cmdName + " --env boot", self.column_width, #"# "+_("show enviroment varibles which has type")+" 'boot'" +\ #".", #self.consolewidth-self.column_width) #}, #{'progAccess':(0,1,2,4,5,6), #'helpChapter':_("Examples"), #'help':pcs(" " + cmdName + " \\\n --set setup_march=x86_64", #self.column_width, "# "+ _("modify some env") + ".", #self.consolewidth-self.column_width) #}, ] self._cl_help__setParamHelp() # Удаляем ненужный аттрибут класса cl_profile.xmlShare self._createElement = False delattr(self, "_createElement") #Название всех сервисов self.allServ = [] self.__setAllServ() def checkPkgs(self,*pkgs): """Check that the package is installed""" pkgDir = '/var/db/pkg' for pkg in pkgs: category,package = pkg.split('/') catDir = os.path.join(pkgDir,category) package = "%s-"%package if not (os.path.exists(catDir) and filter(lambda x:x.startswith(package),os.listdir(catDir))): self.printERROR(_("Package '%s' is not installed")%pkg) return False return True def processOptionsForDatavars(self, options, datavars): '''Обработать опции связанные с переменными окружения Параметры: options словарь опций ( <буква опции>:<значение> обрабатывает буквы 's' для установки параметров 'e' для отображения) datavars объект-хранилище переменных окружнения Возвращаемые значения: True удалось установить указанные параметры False метод вызван для просмотра переменных окружения, или установка переменных окружения прошла с ошибками. ''' # если это установка параметров if 's' in options: # если установки параметрв не произошло if not datavars.flFromCmdParam(options['s']): # вывод print _("Bad enviroment parameters") return False # если опция отображения параметров if 'e' in options: # вывод всех параметров if options['e'] == '*': datavars.printVars() # вывод параметров, используюя фильтр else: datavars.printVars( [i.strip() for i in options['e'].split(':')]) return False return True def handleCheckAccess(self,dataHash): """Дополнительная проверка опций-справок - опция доступна только если в разделах этой справки есть хотябы одна опция Входные параметры: dataHash словарь из списка self.data """ # если эта опция для реализации справки if 'longOption' in dataHash \ and dataHash['longOption'] in self.relOptions: # составляем список разделов которые должны быть не пустые # разделы из relOptions относящиеся к этой опции за исключением # разделов которые надо пропустить (relChapterPass) trueChapters = \ set(self.relOptions[dataHash['longOption']]).difference( \ self.relChapterPass) # перебираем все опции for unit in self.data: # если опция не отностится к выполняемой программе, то # ее пропустить if 'progAccess' in unit and \ not self.progName[self.cmdName] in unit['progAccess']: continue # если опция отностится к необходмой справки if unit['helpChapter'] in trueChapters: # опция справки - доступна return True # если не оказалось не одной опция для разделов этой справки return False # опция доступна, так как не справочная return True def __setAllServ(self): """Записывает в аттрибут self.allServ названия всех сервисов""" sServ = re.compile("\s*([^\s]+)\s*") for par in self.data: if par.has_key('helpChapter') and\ par['helpChapter'] == _("Services") and\ par.has_key('help') and self.access(par): res = sServ.search(par['help']) if res: self.allServ.append(res.group(1)) class servFtp(shareLdap): """Методы севисa Ftp""" relUsDN = 'ou=Users' relServDN = 'ou=Ftp' # Алгоритм шифрования пароля для LDAP пользователя userCrypt = "ssha" # Используемые ldif файлы ldifFileUser = "/usr/lib/calculate/calculate-server/ldif/ftp_user.ldif" ldifFileBase ="/usr/lib/calculate/calculate-server/ldif/ftp_base.ldif" # Динамическая группа Unix для добавления пользователя defaultUnixGroup = {"name":"ftpdomain", "comment":"Default FTP Users"} def __init__(self): shareLdap.__init__(self) self.relDN = self.addDN(self.relServDN,self.ServicesDN) # DN пользователей, относительно базового DN self.relUsersDN = self.addDN(self.relUsDN, self.relDN) self.servUnixObj = servUnix() def setupFtpServer(self, options): """Начальная настройка FTP сервиса""" # Принудительная установка forceOptions = False if options.has_key("f"): forceOptions = True # Создаем объект переменных и начальная проверка if not self.initialChecksSetup(): return False if self.clVars.Get("sr_unix_set") != "on": self.printERROR(_("Unix service is not setuped")) self.printWARNING(_("Setup Unix service")) self.printWARNING(" cl-setup unix") return False # В случае если сервер установлен if self.clVars.Get("sr_ftp_set") == "on" and\ not forceOptions: self.printWARNING (_("WARNING") + ": " +\ _("FTP server is configured")+ ".") return True if not forceOptions: # предупреждение при выполнении этой программы будут изменены # конфигурационные файлы сервиса FTP (программа proftpd) self.printWARNING (_("WARNING") + ": " + _("Executing of the program will change") + " " + _("the configuration files of FTP service") +" ("+ _("program proftpd") + ")." ) # если вы готовы продолжить работу программы нажмите Y если нет n messDialog = \ _("If you are ready to continue executing the program") + ", "+\ _("input 'yes'") +", "+ _("if not 'no'") if not self.dialogYesNo(messDialog): return True else: # делаем backup # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False bakupObj = servLdap() if not bakupObj.backupServer(): return False # Удаляем переменные сервиса в ini файлах self.deleteServiceVarsInFile("ftp") # Cоздаем объект переменные self.createClVars() # Удаляем из автозапуска демона if not self.delDaemonAutostart("proftpd"): return False # останавливаем сервис Mail if not self.stopServices(["ftp"]): return False # Имя устанавливаемого сервиса self.clVars.Set("cl_pass_service","ftp") self.clVars.Write("sr_ftp_set","off") if not self.applyProfilesFromService('ftp'): return False # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False else: if not self.restartLdapServer(): return False # В случае если сервис Samba установлен перезапускаем его if self.clVars.Get("sr_samba_set") == "on": if self.getRunService('samba'): textLines = self.execProg("/etc/init.d/samba restart") if textLines == False: self.printNotOK(_("Restarting") + " Samba ...") return False else: textLines = self.execProg("/etc/init.d/samba start") if textLines == False: self.printNotOK(_("Starting") + " Samba ...") return False # Подключаемся к LDAP cерверу if not shareLdap.getLdapObjInFile(self): return False # Находим в LDAP FTP сервис resSearch = self.searchService() ret = True if resSearch: delDN = self.relDN ret = self.deleteDN(delDN) if ret: self.printOK(_("Remove FTP DN from LDAP Database") + " ...") else: self.printERROR(\ _("Can not remove FTP DN from LDAP Database")) if not ret: return False ldifFile = self.ldifFileBase baseLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): self.ldapObj.ldapAdd(baseLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False # Записываем данные администратора сервиса FTP ldapParser = iniLdapParser() ldapParser.setVar("ftp", {"DN":self.clVars.Get("ld_ftp_dn"), "PASS":self.clVars.Get("ld_ftp_pw")}) self.printOK(_("Added ldif file") + " ...") textLines = [] if self.getRunService('ftp'): textLines = self.execProg("/etc/init.d/proftpd restart") else: textLines = self.execProg("/etc/init.d/proftpd start") if textLines == False: self.printNotOK(_("Starting") + " " + "Proftpd" + " ...") return False else: self.printOK(_("Starting") + " " + "Proftpd" + " ...") # Устанавливаем автозапуск демона if not self.setDaemonAutostart("proftpd"): return False # Устанавливаем переменную для клиента fullHostName = "%s.%s"%(self.clVars.Get('os_net_hostname'), self.clVars.Get('os_net_domain')) self.clVars.Set("cl_remote_ftp",fullHostName,True) #cоздаем рабочую ftp директорию ftpPath = self.clVars.Get("sr_ftp_path") if not os.path.exists(ftpPath): os.makedirs(ftpPath) # Создадим иконку для share fileTxt = "[Desktop Entry]\nIcon=folder-downloads" fileDirectory = os.path.join(ftpPath,".directory") uid = 0 gid = 0 if not self.createUserFile(fileDirectory, fileTxt, uid, gid): return False #cоздаем директорию tmp ftpTmpPath = os.path.join(ftpPath,"tmp") if not os.path.exists(ftpTmpPath): os.makedirs(ftpTmpPath) os.chmod(ftpTmpPath,0777) #cоздаем директорию pub ftpPubPath = os.path.join(ftpPath,"pub") if not os.path.exists(ftpPubPath): os.makedirs(ftpPubPath) os.chmod(ftpPubPath,0755) #запишем переменные для клиента clientVars = ["cl_remote_ftp"] if not self.saveVarsClient(clientVars): return False self.clVars.Write("sr_ftp_set","on") self.printOK(_("FTP service configured") + " ...") return True def searchFtpUser(self, userName): """Находит пользователя сервиса FTP""" resSearch = self.searchLdapDN(userName, self.relUsersDN, "uid") return resSearch def delUserInFtpAndUnix(self, userName, flagDelUnixUser): """Удаляет пользователя Удаляет из FTP и если установлен флаг из Unix """ if self.searchFtpUser(userName): if not self.delUserFtpServer(userName, {}, False): return False if flagDelUnixUser: if not self.servUnixObj.delUserUnixServer(userName, {}, False, False): return False return True def modUserFtpServer(self, userName, options): """Модифицирует настройки пользователя FTP в LDAP""" # Проверим установлен ли сервис FTP if not self.initialChecks("ftp"): return False resSearch = self.searchFtpUser(userName) if not resSearch: self.printERROR( _("User %s is not found in FTP service") % str(userName)) return False # Изменяемые аттрибуты пользователя modAttrs = [] # Изменяем комментарий к пользователю if options.has_key('c'): comment = options['c'] modAttrs += [(ldap.MOD_REPLACE, 'sn', comment), (ldap.MOD_REPLACE, 'cn', comment)] # Изменяем пароль пользователя userPwd = self.getUserPassword(options, "p", "P") if userPwd == False: return False if userPwd: userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) if not userPwdHash: return False if resSearch[0][0][1].has_key('userPassword'): modAttrs.append((ldap.MOD_REPLACE, 'userPassword', userPwdHash)) else: modAttrs.append((ldap.MOD_ADD, 'userPassword', userPwdHash)) if modAttrs: uid = resSearch[0][0][1]['uid'][0] DN = self.addDN("uid="+uid, self.relUsersDN) if not self.modAttrsDN(DN, modAttrs): return False if options.has_key('c'): self.printSUCCESS(_("Modified comment (full name)")) if options.has_key('P') or options.has_key('p'): self.printSUCCESS(_("Modified FTP user password")) return True def modUserFtpPasswd(self, userName, options): """Устанавливает пароль Ftp пользователя и меняет его опции""" # Проверим установлен ли сервис jabber if not self.initialChecks("ftp"): return False resSearch = self.searchFtpUser(userName) if not resSearch: self.printERROR( _("User %s is not found in FTP service") % str(userName)) return False # Изменяемые аттрибуты пользователя modAttrs = [] if not options: optPasswd = {"p":""} userPwd = self.getUserPassword(optPasswd, "p", False) if userPwd == False: return False userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) if not userPwdHash: return False if resSearch[0][0][1].has_key('userPassword'): modAttrs.append((ldap.MOD_REPLACE, 'userPassword', userPwdHash)) else: modAttrs.append((ldap.MOD_ADD, 'userPassword', userPwdHash)) if modAttrs: uid = resSearch[0][0][1]['uid'][0] DN = self.addDN("uid="+userName, self.relUsersDN) if not self.modAttrsDN(DN, modAttrs): return False if not options: self.printSUCCESS(_("Changed FTP user password")) return True return False @adminConnectLdap def delUserFtpServer(self,userName,options,printSuccess=True): """Удаляем FTP пользователя""" # Проверим установлен ли сервис FTP if not self.initialChecks("ftp"): return False # Ищем FTP пользователя resFtp = self.searchFtpUser(userName) if not resFtp: self.printERROR(_("User not exists in FTP service")) return False # FTP директория пользователя ftpUserDir = resFtp[0][0][1]['homeDirectory'][0] ftpPath = self.clVars.Get("sr_ftp_path") if ftpUserDir == ftpPath: ftpUserDir = os.path.join(ftpPath,"pub/users",userName) # Удаляем пользователя delDN = self.addDN("uid=" + userName, self.relUsersDN) if not self.delDN(delDN): return False # Удаляем FTP папку if os.path.exists(ftpUserDir): if self.removeDir(ftpUserDir): if printSuccess: self.printSUCCESS(\ _("FTP user directory %s is removed")%str(ftpUserDir)) if printSuccess: self.printSUCCESS(_("FTP user %s is deleted")%userName) return True @adminConnectLdap def addUserFtpServer(self, userName, options): """Добавляет пользователя FTP""" # Проверим установлен ли сервис FTP if not self.initialChecks("ftp"): return False if self.searchFtpUser(userName): self.printERROR(_("User exists in FTP service")) return False resUnix = self.servUnixObj.searchUnixUser(userName) resPwd = self.servUnixObj.searchPasswdUser(userName) # Пароль пользователя FTP userPwd = self.getUserPassword(options, "p", "P") if userPwd == False: return False flagCreateUnixUser = False if not (resUnix or resPwd): flagCreateUnixUser = True # Добавим пользователя LDAP optUnix = {} # Флаг создания группы по умолчанию flagCreateUnixGroup = False # Группа пользователя if options.has_key('g'): optUnix['g'] = options['g'] else: optUnix['g'] = self.defaultUnixGroup["name"] # Проверяем необходимость переименовывания группы oldGroupName = "ftp domain" if self.servUnixObj.searchUnixGroupName(oldGroupName) and\ not self.servUnixObj.searchUnixGroupName(optUnix['g']): # Переименовываем группу if not self.servUnixObj.modGroupUnixServer(oldGroupName, {'n':optUnix['g']}, False): return False # Проверяем существование группы if not self.servUnixObj.searchUnixGroupName(optUnix['g']): flagCreateUnixGroup = True # Полное имя пользователя if options.has_key('c'): optUnix['c'] = options['c'] # Если нужно создаем новую Unix группу if flagCreateUnixGroup: unixGroupFullName = self.defaultUnixGroup["comment"] optGroupUnix = {"c": unixGroupFullName} if not self.servUnixObj.addGroupUnixServer(optUnix['g'], optGroupUnix, False): self.printERROR (_("Can not add group")+ " " +\ str(optUnix['g']) + _(" in Unix service")) return False if not self.servUnixObj.addUserUnixServer(userName, optUnix, False): self.printERROR (_("Can not add user")+ " " +\ str(userName) + _(" in Unix service")) return False resUnix = self.servUnixObj.searchUnixUser(userName) self.clVars.Set("ur_name", userName) #Полное имя пользователя fullNameUser = self.servUnixObj.fullNameUser if options.has_key('c'): fullNameUser = options['c'] else: if resUnix and resUnix[0][0][1].has_key('cn'): fullNameUser = resUnix[0][0][1]['cn'][0] self.clVars.Set("ur_fio",fullNameUser) if not userPwd: userPwdHash = "crypt{xxx}" else: userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) if not userPwdHash: if flagCreateUnixUser: self.servUnixObj.delUserUnixServer(userName, {}, False, False) return False self.clVars.Set("ur_hash",userPwdHash) # Находим uid и gid пользователя if resUnix: uid = int(resUnix[0][0][1]['uidNumber'][0]) gid = int(resUnix[0][0][1]['gidNumber'][0]) elif resPwd: uid = int(resPwd.split(":")[2]) gid = int(resPwd.split(":")[3]) else: self.printERROR(_("user are not found")) flagError = True self.clVars.Set("ur_id",str(uid)) self.clVars.Set("ur_gid",str(gid)) # Корневая FTP директория ftpDir = self.clVars.Get("sr_ftp_path") # FTP директория пользователя if options.has_key('d') and options.has_key('m'): ftpUserDir = options['d'] if ftpUserDir[0] == "/": ftpUserDir = ftpUserDir[1:] ftpUserDir = os.path.join(ftpDir,ftpUserDir) self.clVars.Set("ur_home_path", ftpUserDir) else: self.clVars.Set("ur_home_path", ftpDir) ldifFile = self.ldifFileUser userLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): #Добавляем пользователя в LDAP self.ldapObj.ldapAdd(userLdif) # не переделывать на else if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False flagError = False # FTP директория пользователя if not options.has_key('d'): ftpUserDir = os.path.join(ftpDir,"pub/users",userName) # Создаем FTP директорию пользователя if options.has_key('m'): if not self.createUserDir(uid, gid, ftpUserDir): flagError = True if flagError: self.delUserInFtpAndUnix(userName, flagCreateUnixUser) self.printERROR(_("Can not add user")) return False if flagCreateUnixUser: self.printSUCCESS(_("Added user in Unix service")) self.printSUCCESS(_("Added user in FTP service")) return True class servRepl(shareLdap): """Методы для работы с репликацией""" # Используемые ldif файлы # Cлужебная ветка: LDAP ldifFileBase = "/usr/lib/calculate/calculate-server/ldif/ldap_base.ldif" # Ветки репликации: Access, Worked ldifFileRepl = "/usr/lib/calculate/calculate-server/ldif/ldap_repl.ldif" # Имя пользователя, машина на которой хостимся ldifFileWorkedUser =\ "/usr/lib/calculate/calculate-server/ldif/ldap_repl_worked_user.ldif" # Реплицируемые почтовые алиасы ldifFileMailUser =\ "/usr/lib/calculate/calculate-server/ldif/ldap_repl_mail.ldif" # Файл для определения выхода пользователя. logOutFile = ".logout" # Файл для управления сервером srvFile = ".calculate/server.env" # Файл для клиента deskFile = ".calculate/desktop.env" # Файл - список файлов профиля пользователя listProfFile = ".calculate/files.txt" # Переменные (/etc/calculate/calculate.env) # которые будут сохранены при rebuild restoreDefaultVar =["sr_ldap_set", "ld_repl_pw", "ld_repl_set", "sr_unix_set", "sr_samba_set","sr_mail_set"] # Переменные (/var/calculate/calculate.env) # которые будут сохранены при rebuild restoreLocalVar = ["sr_samba_domain","sr_samba_netbios", "ld_repl_servers","ld_repl_unix_servers", "ld_repl_samba_servers","ld_repl_ids", "sr_samba_net_allow", "sr_mail_host", "sr_mail_type", "sr_mail_crypt", "sr_mail_relay_set","ld_repl_mail_servers"] # Переменные клиента (/var/calculate/remote/calculate.env) # которые будут сохранены при rebuild restoreRemoteClientVar = ["ld_base_dn", "ld_bind_dn", "ld_bind_pw", "ld_services_dn", "ld_unix_dn", "sr_jabber_crypt", "sr_jabber_host", "sr_jabber_port", "sr_mail_crypt", "sr_mail_host", "sr_mail_port", "sr_mail_send_crypt", "sr_mail_send_host", "sr_mail_send_port", "sr_mail_type", "sr_samba_host", "ur_organization", "ur_signature", "ld_samba_dn"] # файл для удаления данных несуществущих пользователей по cron replCronFile = "replcron" # поддерживаемые сервисы replServices = ("unix", "samba", "mail") # Файлы и директории которые нужно пропускать при нахождении времени # модификации в профиле пользователя skipDatePathsInProfile = list(set([".calculate.ini", os.path.split(srvFile)[0], os.path.split(deskFile)[0], logOutFile])) def __init__(self): shareLdap.__init__(self) # Сервис LDAP self.servLdapObj = servLdap() # Сервис Samba self.servSambaObj = servSamba() # Сервис Unix self.servUnixObj = self.servSambaObj.servUnixObj # Сервис Mail self.servMailObj = servMail() # Cервис Jabber self.servJabberObj = servJabber() # DN ветки Replication/Worked self.relWorkedDN = False # DN ветки Replication/Mail self.relMailDN = False def createClientEnv(self): """Создает объект с клиентскими переменными""" clVars = cl_base.DataVars() clVars.flServer() calculate_ini = self.clVars.Get("cl_env_path") remoteIni = "" if calculate_ini and type(calculate_ini) == types.ListType: remoteIni = calculate_ini[0] if remoteIni: # проверить сущестование ini файла if os.path.exists(remoteIni): # получаем активную секцию set_act_section = set(['client']) # получить объект настроенный на ini config = cl_base.iniParser(remoteIni) # получаем все секции из конфигурационного файла allsect = config.getAllSectionNames() if not allsect: return (True, clVars) # находим встречающиеся у обоих секции act_sect = tuple(set(allsect)& set_act_section) # получаем все переменные из всех секций for section in act_sect: allvars = config.getAreaVars(section) if allvars == False: return (False, remoteIni) # принудительно переписать все переменные окружения # полученные из ini for (k,v) in allvars.items(): k = k.encode("UTF-8") v = v.encode("UTF-8") clVars.Set(k, cl_utils.convertStrListDict(v), True) return (True, clVars) def prepAndSaveEnv(self): """Подготовка переменных и их запись в файлы в случае rebuild""" # Cоздаем объект переменные def removeNameFoundText(findText, listName): """Удаляет элементы списка. Будут удалены элементы названии которых присутствует текст (findText) """ outListName = [] for name in listName: if not findText in name: outListName.append(name) return outListName # Cоздаем объект переменные self.createClVars() if self.clVars.Get("ld_repl_set") != "on": self.printERROR(_("Replication off in backup file")) return False # Cоздание объекта клиентских переменных cond, clVarsClient = self.createClientEnv() if not cond: self.printERROR(_("Variable incorrect in file %s")%clVarsClient) return False # Записываем переменные клиента в переменные сервера for varName in self.restoreRemoteClientVar: self.clVars.Set(varName, clVarsClient.Get(varName), True) clVarsClient.Get("ur_organization") # Модификация переменных replSambaServers = self.clVars.Get("ld_repl_samba_servers") if replSambaServers: replSambaServers = replSambaServers.split(",") replUnixServers = self.clVars.Get("ld_repl_unix_servers") if replUnixServers: replUnixServers = replUnixServers.split(",") replMailServers = self.clVars.Get("ld_repl_mail_servers") if replMailServers: replMailServers = replMailServers.split(",") hostName = self.clVars.Get('os_net_hostname') domain = self.clVars.Get('os_net_domain') serviceRepl = "" fullHostName = "%s.%s"%(hostName,domain) if not fullHostName in replSambaServers: if fullHostName in replUnixServers: serviceRepl = "unix" if fullHostName in replMailServers: serviceRepl = "unix_mail" else: serviceRepl = "samba" if fullHostName in replMailServers: serviceRepl = "samba_mail" if not serviceRepl and fullHostName in replMailServers: serviceRepl = "mail" if not serviceRepl: self.printERROR(\ _("Not found this replication server %s in backup file")%fullHostName) return False if serviceRepl == "unix": self.restoreDefaultVar = removeNameFoundText("samba", self.restoreDefaultVar) self.restoreDefaultVar = removeNameFoundText("mail", self.restoreDefaultVar) self.restoreLocalVar = removeNameFoundText("mail", self.restoreLocalVar) self.restoreLocalVar = removeNameFoundText("samba", self.restoreLocalVar) self.restoreRemoteClientVar = [] # Очищаем переменные self.clVars.Set("ld_repl_mail_servers","",True) self.clVars.Set("ld_repl_samba_servers","",True) # Устанавливаем переменную серверы репликации # равной почтовым серверам репликации - Mail серверы репликации allReplServers = \ list(set(self.clVars.Get("ld_repl_servers").split(",")) -\ set(self.clVars.Get("ld_repl_mail_servers").split(","))) self.clVars.Set("ld_repl_servers" ,",".join(allReplServers), True) # При вызове значения переменной будет перезапущен метод заполнения self.reloadDefaultVar("ld_repl_ids") elif serviceRepl == "samba": self.clVars.Set('sr_samba_netbios', "%s-cds"%hostName, True) self.clVars.Set('sr_samba_host',fullHostName, True) self.restoreDefaultVar = removeNameFoundText("mail", self.restoreDefaultVar) self.restoreLocalVar = removeNameFoundText("mail", self.restoreLocalVar) # Получаем от пользователя доверительные сети для сервиса Samba # Переназначаем объект переменных print _("Replications servers for Samba: %s")\ % " ".join(replSambaServers) self.servSambaObj.clVars = self.clVars if not self.servSambaObj.getAllowNet(): return False # Очищаем переменные self.clVars.Set("ld_repl_mail_servers","",True) # Устанавливаем переменную серверы репликации # равной почтовым серверам репликации - Mail серверы репликации allReplServers = \ list(set(self.clVars.Get("ld_repl_servers").split(",")) -\ set(self.clVars.Get("ld_repl_mail_servers").split(","))) self.clVars.Set("ld_repl_servers" ,",".join(allReplServers), True) # При вызове значения переменной будет перезапущен метод заполнения self.reloadDefaultVar("ld_repl_ids") elif serviceRepl == "mail": self.restoreDefaultVar = removeNameFoundText("samba", self.restoreDefaultVar) self.restoreDefaultVar = removeNameFoundText("unix", self.restoreDefaultVar) self.restoreLocalVar = removeNameFoundText("unix", self.restoreLocalVar) self.restoreLocalVar = removeNameFoundText("samba", self.restoreLocalVar) self.restoreRemoteClientVar = [] # Получаем от пользователя доверительные сети для сервиса Mail # Переназначаем объект переменных print _("Replications servers for Mail: %s")\ % " ".join(replMailServers) self.servMailObj.clVars = self.clVars if not self.servMailObj.getAllowNet(): return False self.clVars.Set('sr_mail_host', fullHostName, True) # Получаем имя хоста для сервиса Mail if not self.servMailObj.getHostName(): return False # Указываем что это почтовый релей self.clVars.Set('sr_mail_relay_set', "on", True) # Устанавливаем переменную серверы репликации # равной почтовым серверам репликации self.clVars.Set("ld_repl_servers", self.clVars.Get("ld_repl_mail_servers"), True) # Обнуляем ненужные переменные self.clVars.Set("ld_repl_samba_servers","",True) self.clVars.Set("ld_repl_unix_servers","",True) # При вызове значения переменной будет перезапущен метод заполнения self.reloadDefaultVar("ld_repl_ids") elif serviceRepl == "unix_mail": self.restoreDefaultVar = removeNameFoundText("samba", self.restoreDefaultVar) self.restoreLocalVar = removeNameFoundText("samba", self.restoreLocalVar) self.restoreLocalVar = removeNameFoundText("sr_mail_relay_set", self.restoreLocalVar) self.restoreRemoteClientVar = [] # Получаем от пользователя доверительные сети для сервиса Mail # Переназначаем объект переменных print _("Replications servers for Mail: %s")\ % " ".join(replMailServers) self.servMailObj.clVars = self.clVars if not self.servMailObj.getAllowNet(): return False self.clVars.Set('sr_mail_host', fullHostName, True) # Получаем имя хоста для сервиса Mail if not self.servMailObj.getHostName(): return False elif serviceRepl == "samba_mail": self.clVars.Set('sr_samba_netbios', "%s-cds"%hostName, True) self.clVars.Set('sr_samba_host',fullHostName, True) self.restoreLocalVar = removeNameFoundText("sr_mail_relay_set", self.restoreLocalVar) # Получаем от пользователя доверительные сети для сервиса Samba # Переназначаем объект переменных print _("Replications servers for Samba: %s")\ % " ".join(replSambaServers) self.servSambaObj.clVars = self.clVars if not self.servSambaObj.getAllowNet(): return False # Получаем от пользователя доверительные сети для сервиса Mail # Переназначаем объект переменных print _("Replications servers for Mail: %s")\ % " ".join(replMailServers) self.servMailObj.clVars = self.clVars if not self.servMailObj.getAllowNet(): return False self.clVars.Set('sr_mail_host', fullHostName, True) # Получаем имя хоста для сервиса Mail if not self.servMailObj.getHostName(): return False # Находим пути к env файлам envPaths = self.clVars.Get("cl_env_path") # Удаляем env файлы for path in envPaths: if os.path.exists(path): os.remove(path) flagError = False # Записываем переменные сервера for varName in self.restoreDefaultVar: if not self.clVars.Write(varName,self.clVars.Get(varName),True): flagError = True break if flagError: self.printERROR(_("Variable '%s'")%varName + " " +\ _("can not be recorded in the file %s") %envPaths[2]) return False for varName in self.restoreLocalVar: if not self.clVars.Write(varName, self.clVars.Get(varName),True,'local'): flagError = True break if flagError: self.printERROR(_("Variable '%s'")%varName + " " +\ _("can not be recorded in the file %s") %envPaths[2]) return False # Записываем переменные клиента if self.restoreRemoteClientVar: if not self.saveVarsClient(self.restoreRemoteClientVar): return False # Выставляем права на ресурс remote if "samba" in serviceRepl: cl = self.staticUsers["client"] # Если нет то создадим директорию /var/calculate/remote remoteEnvFile = self.clVars.Get("cl_env_path")[0] remotePath = os.path.split(remoteEnvFile)[0] if not os.path.exists(remotePath): os.makedirs(remotePath) # права и владелец /var/calculate/remote if os.path.exists(remotePath): os.chown(remotePath,0,int(cl.gid)) os.chmod(remotePath,02755) # изменяем владельца remote на client if not os.path.exists(remoteEnvFile): fd = os.open(remoteEnvFile, os.O_CREAT) os.close(fd) os.chmod(remoteEnvFile, 0640) if os.path.exists(remoteEnvFile): os.chown(remoteEnvFile,0,int(cl.gid)) return True @adminConnectLdap def isSysDNExists(self): """Существует ли служебная ветка LDAP""" sysLogin = self.clVars.Get("ld_ldap_login") searchDN = self.searchLdapDN(sysLogin, self.ServicesDN, 'ou') if searchDN: return True else: return False @adminConnectLdap def getProfileDirs(self, userName): """Выводит директории профилей для пользователя""" profileDir = os.path.join(self.clVars.Get("sr_samba_linprof_path"), userName) if not os.path.exists(profileDir): return False return filter(lambda x:\ os.path.exists(os.path.join(x, self.logOutFile)) or \ os.path.exists(os.path.join(x, self.srvFile)) or\ os.path.exists(os.path.join(x, self.deskFile)), [profileDir] + map(lambda x: os.path.join(profileDir, x),\ filter(lambda x:\ os.path.isdir(os.path.join(profileDir, x)) ,\ os.listdir(profileDir)))) @adminConnectLdap def deleteLogoutFile(self, userName, logoutFile): """Удаляет .logout файл""" if os.path.exists(logoutFile): try: FD = open(logoutFile) exitStr = FD.read() FD.close() except: return False if exitStr: exitStr = exitStr.strip() else: exitStr = "EMPTY" try: os.remove(logoutFile) except: return False return exitStr return "NOFILE" def createUserDirs(self, userName): """Если пользовательские директории не существуют то создаем их """ resSearchUnix = self.servUnixObj.searchUnixUser(userName) resPasswd = False uid = None gid = None if resSearchUnix: uid = int(resSearchUnix[0][0][1]['uidNumber'][0]) gid = int(resSearchUnix[0][0][1]['gidNumber'][0]) else: resPasswd = self.servUnixObj.searchPasswdUser(userName) if resPasswd: uid = int(resPasswd.split(":")[2]) gid = int(resPasswd.split(":")[3]) if uid == None or gid == None: print _("User %s not found in Unix service") return False winProfDir =\ os.path.join(self.clVars.Get("sr_samba_winprof_path"), userName) linProfDir =\ os.path.join(self.clVars.Get("sr_samba_linprof_path"), userName) userHomeDir =\ os.path.join(self.clVars.Get("sr_samba_home_path"), userName) userNetlogonDir =\ os.path.join(self.clVars.Get("sr_samba_winlogon_path"), userName) userTrashDir =\ os.path.join(self.clVars.Get("sr_samba_share_path"), ".Trash-%d"%uid) userTrashDirFtp =\ os.path.join(self.clVars.Get("sr_ftp_path"), ".Trash-%d"%uid) userDirs = [("home",userHomeDir), ("netlogon",userNetlogonDir), ("win_prof",winProfDir), ('lin_prof',linProfDir), ('trash',userTrashDir), ('ftp',userTrashDirFtp)] flagError = False for name, userDir in userDirs: if name == "ftp": if self.clVars.Get("sr_ftp_set") != "on": continue if not os.path.exists(userDir): if not self.createUserDir(uid, gid, userDir): flagError = True break if name == "home": # Cоздаем иконку в домашней директории fileTxt = "[Desktop Entry]\nIcon=user-home" fileDirectory = os.path.join(userDir,".directory") if not self.createUserFile(fileDirectory, fileTxt, uid, gid): flagError = True break elif name == "netlogon": # Создаем start.cmd netbios = self.clVars.Get("sr_samba_netbios") netbios = netbios.upper() fileTxt='NET USE R: /D\r\nNET USE R: \\\\%s\\share\ \r\nNET USE T: /D\r\nNET VIEW \\\\%s | find "ftp"\r\n\ if %%errorlevel%%==0 NET USE T: \\\\%s\\ftp' %(netbios,netbios,netbios) fileDirectory = os.path.join(userDir,"start.cmd") if not self.createUserFile(fileDirectory, fileTxt, uid, gid): flagError = True break if flagError: return False return True @adminConnectLdap def isReplDNExists(self): """Существует ли ветка репликации LDAP""" if not self.isSysDNExists(): return False sysLogin = self.clVars.Get("ld_ldap_login") replLogin = self.clVars.Get("ld_repl_login") relSysDn = "ou=%s,%s"%(sysLogin,self.ServicesDN) searchReplDN = self.searchLdapDN(replLogin, relSysDn, 'ou') if not searchReplDN: return False else: return True @adminConnectLdap def isReplMailDNExists(self): """Существуют ли ветка репликации Replication/Mail""" if not self.isReplDNExists(): return False sysLogin = self.clVars.Get("ld_ldap_login") replLogin = self.clVars.Get("ld_repl_login") replMailLogin = self.clVars.Get("ld_repl_mail_login") relSysDn = "ou=%s,ou=%s,%s"%(replLogin,sysLogin,self.ServicesDN) searchReplDN = self.searchLdapDN(replMailLogin, relSysDn, 'ou') if not searchReplDN: return False else: return True @adminConnectLdap def isReplWorkedDNExists(self): """Существуют ли ветка репликации Replication/Worked""" if not self.isReplDNExists(): return False sysLogin = self.clVars.Get("ld_ldap_login") replLogin = self.clVars.Get("ld_repl_login") replMailLogin = self.clVars.Get("ld_repl_worked_login") relSysDn = "ou=%s,ou=%s,%s"%(replLogin,sysLogin,self.ServicesDN) searchReplDN = self.searchLdapDN(replMailLogin, relSysDn, 'ou') if not searchReplDN: return False else: return True @adminConnectLdap def addSysDN(self): """Добавляет служебную ветку в LDAP если она не существует""" if not self.isSysDNExists(): ldifFile = self.ldifFileBase baseLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): self.ldapObj.ldapAdd(baseLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False return True @adminConnectLdap def delSysDN(self): """Удаляет служебную ветку в LDAP если она существует""" if self.isSysDNExists(): sysLdapOU = "ou=%s"%self.clVars.Get("ld_ldap_login") sysLdapRelDN = self.addDN(sysLdapOU, self.ServicesDN) if not self.deleteDN(sysLdapRelDN): self.printERROR(_("Can not remove 'Services/LDAP' DN")) return False return True @adminConnectLdap def addReplDN(self, clVars=False): """Добавляет ветки репликации в LDAP""" if clVars: self.clVars = clVars #Добавляем служебную ветку if not self.addSysDN(): return False #Если ветка репликации не существует добавляем её if not self.isReplDNExists(): ldifFile = self.ldifFileRepl baseLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): self.ldapObj.ldapAdd(baseLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False # Если ветка Replication/Mail не существует - добавляем ее if not self.isReplMailDNExists(): errorMessage = _("Can not append Replication/Mail branch in LDAP") entry = [('objectclass', ['top','organizationalUnit']), ('ou', ['%s' %self.clVars.Get("ld_repl_mail_login")])] try: self.conLdap.add_s(self.clVars.Get("ld_repl_mail_dn"), entry) except ldap.LDAPError, e: self.printERROR(_("LDAP Error") + ": " + e[0]['desc'].strip()) self.printERROR(errorMessage) return False except: self.printERROR(errorMessage) return False # Если ветка Replication/Worked не существует - добавляем ее if not self.isReplWorkedDNExists(): errorMessage = _("Can not append Replication/Worked branch in LDAP") entry = [('objectclass', ['top','organizationalUnit']), ('ou', ['%s' %self.clVars.Get("ld_repl_worked_login")])] try: self.conLdap.add_s(self.clVars.Get("ld_repl_worked_dn"), entry) except ldap.LDAPError, e: self.printERROR(_("LDAP Error") + ": " + e[0]['desc'].strip()) self.printERROR(errorMessage) return False except: self.printERROR(errorMessage) return False return True @adminConnectLdap def getRelWorkedDN(self): """Получаем относительный DN ветки Worked""" if not self.relWorkedDN: sysLogin = self.clVars.Get("ld_ldap_login") replLogin = self.clVars.Get("ld_repl_login") repWorkedlLogin = self.clVars.Get("ld_repl_worked_login") self.relWorkedDN = "ou=%s,ou=%s,ou=%s,%s" %(repWorkedlLogin,\ replLogin,sysLogin,self.ServicesDN) return self.relWorkedDN @adminConnectLdap def getRelMailDN(self): """Получаем относительный DN ветки Replication/Mail""" if not self.relMailDN: sysLogin = self.clVars.Get("ld_ldap_login") replLogin = self.clVars.Get("ld_repl_login") replMailLogin = self.clVars.Get("ld_repl_mail_login") self.relMailDN = "ou=%s,ou=%s,ou=%s,%s" %(replMailLogin,\ replLogin,sysLogin,self.ServicesDN) return self.relMailDN def searchWorkedUser(self,userName): """Находит пользователя в ветке Worked""" relWorkedDN = self.getRelWorkedDN() resSearch = self.searchLdapDN(userName, relWorkedDN, "uid") return resSearch def searchMailAlias(self,userName): """Находит alias пользователя в ветке Replication/Mail""" relMailDN = self.getRelMailDN() resSearch = self.searchLdapDN(userName, relMailDN, "cn") return resSearch def searchMailAddress(self, userMail): """Находит адрес пользователя в ветке Replication/Mail""" relMailDN = self.getRelMailDN() resSearch = self.searchLdapDN(userMail, relMailDN, "mail") if not resSearch: resSearch = self.searchLdapDN(userMail, relMailDN, "mailAlternateAddress") if not resSearch: resSearch = self.searchLdapDN(userMail, relMailDN, "rfc822member") return resSearch @adminConnectLdap def delReplWorkedUser(self, userName, fullDel=True): """Удаляет пользователя из ветки Worked""" flagError = False # Полное удаление пользователя из ветки relWorkedDN = self.getRelWorkedDN() if fullDel: foundUsers = self.searchWorkedUser(userName+"@*") if foundUsers: deleteUserNames = map(lambda x: x[0][1]["uid"][0], foundUsers) for delUser in deleteUserNames: delDN = self.addDN("uid=" + delUser, relWorkedDN) if not self.delDN(delDN): flagError = True break if not flagError and self.searchWorkedUser(userName): delDN = self.addDN("uid=" + userName, relWorkedDN) if not self.delDN(delDN): flagError = True if flagError: return False return True @adminConnectLdap def delReplMailAlias(self, userName): """Удаляет почтовый алиас""" rez = self.searchMailAlias(userName) if rez: relMailDN = self.getRelMailDN() delDN = self.addDN("cn=" + userName, relMailDN) if not self.delDN(delDN): return False return True def deleteVars(self): """Удаляем переменные репликации Объект self.clVars должен определен перед вызовом """ self.clVars.Delete("ld_repl_servers","local","server") self.clVars.Delete("ld_repl_samba_servers","local","server") self.clVars.Delete("ld_repl_mail_servers","local","server") self.clVars.Delete("ld_repl_unix_servers","local","server") self.clVars.Delete("ld_repl_pw") self.clVars.Delete("ld_repl_set") self.clVars.Delete("ld_repl_ids","local","server") return True @adminConnectLdap def renameReplMailAlias(self, oldName, newName): """Изменяем название алиаса в Replication/Mail""" rez = self.searchMailAlias(oldName) if not rez: return True email = rez[0][0][1]["rfc822member"][0] splEmail = email.split("@") attrAppend = [] relMailDN = self.getRelMailDN() oldDN = self.addDN("cn=" + oldName, relMailDN) if len(splEmail)==2: emailDomen = splEmail[1] newEmail = "%s@%s" %(newName,emailDomen) attrAppend.append((ldap.MOD_REPLACE, 'rfc822member', newEmail)) attrAppend.append((ldap.MOD_REPLACE, 'mailMessageStore', newName + "/")) if not self.modAttrsDN(oldDN, attrAppend): return False newFirstDn = "cn=" + newName res = self.modifyElemDN(oldDN, newFirstDn) if not res: return False return True @adminConnectLdap def deleteHideHosts(self, aliasName): """Удаляет свойство алиаса фильтр хостов""" rez = self.searchMailAlias(aliasName) if not rez: return True if rez[0][0][1].has_key('filtersender'): attrDelete = [] relMailDN = self.getRelMailDN() aliasDN = self.addDN("cn=%s"%aliasName, relMailDN) attrDelete.append((ldap.MOD_DELETE, 'filtersender', None)) if not self.modAttrsDN(aliasDN, attrDelete): return False return True @adminConnectLdap def modReplMailAlias(self, userName, srcMails, filterHosts=[]): """Изменяем запись в Replication/Mail (имя пользователя, список почтовых адресов пользователя""" rez = self.searchMailAlias(userName) if not rez: # Если алиас не найден создаем его return self.addReplMailAlias(userName, srcMails, filterHosts) mailHost = self.clVars.Get('sr_mail_host') if not mailHost: hostName = self.clVars.Get('os_net_hostname') domain = self.clVars.Get('os_net_domain') fullHostName = "%s.%s"%(hostName,domain) self.clVars.Set('sr_mail_host',fullHostName,True) mailHost = fullHostName # Получаем почтовые алиасы (почтовые адреса на других серверах) userMails = filter(lambda x:\ len(x.split("@"))==2 and x.split('@')[1] != mailHost,\ filter(lambda x: "@" in x, srcMails)) if userMails: # Внешний почтовый адрес пользователя (первый в списке) userMail = userMails[0] # Убирает первый адрес из списка userMails = list(set(filter(lambda x: x != userMail, userMails))) attrAppend = [] attrDelete = [] attrReplace = [] if filterHosts: domain = self.clVars.Get('os_net_domain') # Если необходимо добавляем домен к именам хостов fHosts = map(lambda x: (not '.' in x and x+"."+domain) or x, filterHosts) for host in fHosts: attrAppend.append((ldap.MOD_ADD, 'filtersender', host)) if rez[0][0][1].has_key('filtersender'): attrDelete.append((ldap.MOD_DELETE, 'filtersender', None)) email = rez[0][0][1]["mail"][0] altEmails = rez[0][0][1]["mailAlternateAddress"] # Удаляем альтернативные адреса, кроме первого for altEmail in altEmails: if email != altEmail: attrDelete.append( (ldap.MOD_DELETE, 'mailAlternateAddress', altEmail)) # Заменяем первый адрес attrReplace.append((ldap.MOD_REPLACE, 'mail',userMail)) attrReplace.append((ldap.MOD_REPLACE, 'mailAlternateAddress', userMail)) relMailDN = self.getRelMailDN() aliasDN = self.addDN("cn=%s"%userName,relMailDN) # Добавляем альтернативные адреса for mail in userMails: attrAppend.append((ldap.MOD_ADD, 'mailAlternateAddress', mail)) modAttrs = attrDelete + attrReplace + attrAppend if not self.modAttrsDN(aliasDN, modAttrs): return False else: relMailDN = self.getRelMailDN() aliasDN = self.addDN("cn=%s"%userName,relMailDN) # Удаляем почтовый алиас if not self.delDN(aliasDN): return False return True @adminConnectLdap def addReplMailAlias(self, userName, srcMails , filterHosts=[]): """Добавляем запись в Replication/Mail (имя пользователя, список почтовых адресов пользователя""" rez = self.searchMailAlias(userName) if not rez: ldifFile = self.ldifFileMailUser self.clVars.Set("ur_name", userName) mailHost = self.clVars.Get('sr_mail_host') if not mailHost: hostName = self.clVars.Get('os_net_hostname') domain = self.clVars.Get('os_net_domain') fullHostName = "%s.%s"%(hostName,domain) self.clVars.Set('sr_mail_host',fullHostName,True) mailHost = fullHostName # Получаем почтовые алиасы (почтовые адреса на других серверах) userMails = filter(lambda x:\ len(x.split("@"))==2 and x.split('@')[1] != mailHost,\ filter(lambda x: "@" in x, srcMails)) if userMails: # Внешний почтовый адрес пользователя (первый в списке) userMail = userMails[0] # Убираем первый адрес из списка userMails = list(set(filter(lambda x: x != userMail, userMails))) self.clVars.Set("ur_mail", userMail) baseLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): self.ldapObj.ldapAdd(baseLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": "+self.ldapObj.getError().strip() return False modAttrs = [] relMailDN = self.getRelMailDN() aliasDN = self.addDN("cn=%s"%userName,relMailDN) for mail in userMails: modAttrs.append((ldap.MOD_ADD, 'mailAlternateAddress', mail)) if filterHosts: domain = self.clVars.Get('os_net_domain') # Если необходимо добавляем домен к именам хостов fHosts = map(lambda x: (not '.' in x and x+"."+domain) or x, filterHosts) for host in fHosts: modAttrs.append((ldap.MOD_ADD, 'filtersender', host)) res = self.modAttrsDN(aliasDN, modAttrs) # Если ошибка то удаляем почтовый алиас if not res: self.delReplMailAlias(userName) return False return True @adminConnectLdap def addReplWorkedUser(self, userName): """Добавляем запись в Worked ветку (uid, имя сервера)""" rez = self.searchWorkedUser(userName) if not rez: ldifFile = self.ldifFileWorkedUser self.clVars.Set("ur_name", userName) baseLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): self.ldapObj.ldapAdd(baseLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False rez = self.searchWorkedUser(userName) replHost = self.clVars.Get("ld_repl_host") if not replHost: print _("Variable Error: not set a variable ld_repl_host") return False if rez: host = rez[0][0][1]['host'][0] if host != replHost: # Изменяемые аттрибуты modAttrs = [(ldap.MOD_REPLACE, 'host', replHost)] relWorkedDN = self.getRelWorkedDN() DN = self.addDN("uid="+userName, relWorkedDN) if not self.modAttrsDN(DN, modAttrs): return False else: print _("Can not add user %s in branch 'Replication'")%userName return False return True def maxDateAndListInDir(self, scanDir, listFiles, skipPathTime=[], checkTime=True, prefix=None, maxTime=None, flagDir=False): """Время последней модификации внутри директории scanDir Генерация списка файлов и директорий """ startCheckTime = checkTime if not prefix: prefix = os.path.join(scanDir,"") if startCheckTime and not maxTime: maxTime = 0 if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]): for fileOrDir in os.listdir(scanDir): absPath = os.path.join(scanDir,fileOrDir) relPath = absPath.split(prefix)[1] listFiles.append(relPath) if startCheckTime is True: checkTime = True for skipPath in skipPathTime: if relPath.startswith(skipPath): checkTime = False break #print absPath stInfo = os.lstat(absPath) statInfo = stInfo[stat.ST_MODE] if stat.S_ISREG(statInfo): if checkTime: curTime = stInfo[stat.ST_CTIME] if curTime>maxTime: maxTime = curTime elif stat.S_ISDIR(statInfo): if checkTime: curTime = stInfo[stat.ST_CTIME] if curTime>maxTime: maxTime = curTime maxTime = self.maxDateAndListInDir(absPath, listFiles, skipPathTime, checkTime, prefix, maxTime, True) elif stat.S_ISLNK(statInfo): if checkTime: curTime = stInfo[stat.ST_CTIME] if curTime>maxTime: maxTime = curTime return maxTime def setListFilesAndDatesInUserProfiles(self, userName): """Устанавливает дату профиля в конфигурационный файл клиента а также спискок файлов профиля пользователя """ listFiles = [] def printErrMessages(error): """Печать сообщений о ошибках""" errors = error.splitlines() for err in errors: self.printERROR(err) resSearchUnix = self.servUnixObj.searchUnixUser(userName) uid = None gid = None if resSearchUnix: uid = int(resSearchUnix[0][0][1]['uidNumber'][0]) gid = int(resSearchUnix[0][0][1]['gidNumber'][0]) else: resPasswd = self.servUnixObj.searchPasswdUser(userName) if resPasswd: uid = int(resPasswd.split(":")[2]) gid = int(resPasswd.split(":")[3]) if uid == None or gid == None: print _("User %s not found in Unix service") return False linProfDir =\ os.path.join(self.clVars.Get("sr_samba_linprof_path"), userName) # Если чистая директория профиля то пропускаем if not os.listdir(linProfDir): return True for relDirProf in os.listdir(linProfDir): dirProf = os.path.join(linProfDir,relDirProf) if os.path.isdir(dirProf): # Находим максимальную дату в каждом профиле пользователя # и создаем список файлов listFiles = [] desktopFile = os.path.join(dirProf,self.deskFile) maxDate = self.maxDateAndListInDir(dirProf,listFiles, self.skipDatePathsInProfile) # Записываем список файлов # calculate/files.txt listProfFile = os.path.join(dirProf, self.listProfFile) # Создаем директорию если необходимо listProfDir = os.path.split(listProfFile)[0] if not os.path.exists(listProfDir): os.makedirs(listProfDir) os.chown(listProfDir,uid,gid) try: open(listProfFile,"w").write("\n".join(listFiles)) except: self.printERROR(_("Can not open %s")%listProfFile) return False stInfo = os.lstat(listProfFile) # Меняем права на файл if uid != stInfo.st_uid or gid != stInfo.st_gid: os.chown(listProfFile,uid,gid) # Записываем дату профиля в файл .calculate/desktop.env # Создаем директорию если необходимо desktopDir = os.path.split(desktopFile)[0] if not os.path.exists(desktopDir): os.makedirs(desktopDir) os.chown(desktopDir, uid, gid) strDate = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(maxDate)) # Изменяем дату профиля data = {"date":strDate} objConfig = cl_base.iniParser(desktopFile) objConfig.setVar("main", data) error = objConfig.getError() if error: printErrMessages(error) return False stInfo = os.lstat(desktopFile) # Меняем права на файл if uid != stInfo.st_uid or gid != stInfo.st_gid: os.chown(desktopFile, uid, gid) return True def packUserProfile(self,pathProfile,strArchDate,strCurrentTime,objConfig): """Создает инкрементальный архив профиля пользователя с определенной даты""" # Текущий путь extSuccess = "gz" extProcess = "process" pathProg = os.getcwd() strCurrentTimeRepl = strCurrentTime.replace(".","_") prevPath, osShortName = os.path.split(pathProfile) archPathTmp = os.path.join(prevPath, "profile.%s.%s.tar"\ %(osShortName, strCurrentTimeRepl)) # имя файла архива в процессе архивации archPathSuccess = "%s.%s"%(archPathTmp,extSuccess) # имя файла архива - после архивации archPathProcess = "%s.%s"%(archPathTmp,extProcess) # Если файлы архивов существует то удаляем их pathsRemove = (archPathProcess, archPathSuccess) for rmPath in pathsRemove: if os.path.exists(rmPath): os.remove(rmPath) execStr = 'tar --exclude=.calculate/server.env \ --newer "%s" -czf %s . &>/dev/null'\ %(strArchDate, archPathProcess) os.chdir(pathProfile) # Выполняем архивацию ret = os.system(execStr) # восстановление текущего пути os.chdir(pathProg) # При успешной архивации переименовываем файл архива if os.path.exists(archPathProcess): os.rename(archPathProcess, archPathSuccess) if ret: self.printERROR(_("Can not create %s")%archPath) return False else: return True def execLoginUser(self, userName, flagRepl, flagMakeDir): """Действия на сервере при входе пользователя в сеанс""" # Поиск пользователя в Samba сервисе if not self.servSambaObj.searchSambaUser(userName): self.printERROR(_("Samba user %s is not found")%str(userName)) return False # Создаем пользовательские директории на сервере if not self.createUserDirs(userName): self.printERROR(_("Can not create user %s directories")\ %str(userName)) return False # В случае репликации if not flagMakeDir and flagRepl: # Устанавливаем время модификации профиля в конф. файл # desktop.env для всех профилей пользователя # а также получаем список файлов if not self.setListFilesAndDatesInUserProfiles(userName): return False self.printSUCCESS(_("User %s login")%userName) return True def execLogoutUser(self, userName, flagRepl): """Действия на сервере при выходе пользователя из сеанса""" def printErrMessages(error): """Печать сообщений о ошибках""" errors = error.splitlines() for err in errors: self.printERROR(err) def setWorkedUser(userName, dirLogOut, profileDir): """Запись пользователя в Worked ветку LDAP""" if dirLogOut == profileDir: userLogin = userName else: clientOs = os.path.split(dirLogOut)[1].\ replace(".","") # если есть старый пользователь в ветке # Worked и клиентская система CLD - # удаляем старого пользователя if self.searchWorkedUser(userName) and\ clientOs=="CLD": # Удаляем пользователя из ветки # второй параметр False if not self.delReplWorkedUser(userName, False): self.printERROR(_("Can not \ remove user %s in the LDAP branch 'Worked'")%str(userName)) return False userLogin = "%s@%s"%(userName,clientOs) # Добавляем пользователя в ветку репликации if not self.addReplWorkedUser(userLogin): self.printERROR(_("Can not add user \ %s in LDAP branch 'Replication'")%str(userName)) return False return True # Поиск пользователя в Samba сервисе if not self.servSambaObj.searchSambaUser(userName): self.printERROR(_("Samba user %s is not found")%str(userName)) return False # Директория хранения профилей profileDir = os.path.join(\ self.clVars.Get("sr_samba_linprof_path"), userName) # получаем директории профилей dirsLogOut= self.getProfileDirs(userName) flagLogOut = True # Удаляем файлы .logout for dirLogOut in dirsLogOut: logoutFile = os.path.join(dirLogOut, self.logOutFile) retStr = self.deleteLogoutFile(userName, logoutFile) if not retStr: self.printERROR(\ _("No access to the file %s")%logoutFile) return False # Читаем данные из ~/.calculate/desktop.env файла desktopFile = os.path.join(dirLogOut,self.deskFile) if os.path.exists(desktopFile): # Получаем переменные из env файла txtDskConfig = cl_base.iniParser(desktopFile) # Статус профиля profStatus = txtDskConfig.getVar("main","status_sync") if profStatus: # Очищаем статус # txtDskConfig.delVar("main","status_sync") # Если нет .logout файла или он пуст if retStr in ("NOFILE", "EMPTY"): retStr = profStatus.upper() error = txtDskConfig.getError() if error: printErrMessages(error) return False if retStr == "SUCCESS": varsPackDict = {} # Управление сервером srvFile = os.path.join(dirLogOut,self.srvFile) if os.path.exists(srvFile): # Поддерживаемые секции которые не нужно удалять supportSections = [] # Получим текущую дату strCurrentTime = time.strftime(\ "%Y-%m-%d %H:%M:%S",time.localtime(time.time())) # Получаем переменные из env файла txtConfig = cl_base.iniParser(srvFile) # Cловарь переменных из файла для изменения пароля # пользователя sectionPwd = ["command","passwd_samba"] varsPwdDict = txtConfig.getAreaVars(sectionPwd) # Если включена репликация if flagRepl: # Команда для упаковки профиля sectionPack = ["command","pack"] varsPackDict = txtConfig.getAreaVars(sectionPack) error = txtConfig.getError() if error: printErrMessages(error) return False # Изменение пароля пользователя if varsPwdDict: # Если run=on выполняем команду if varsPwdDict.get("run") == "on": supportSections.append(",".join(sectionPwd)) if self.changeUserPassword(userName, varsPwdDict, srvFile,strCurrentTime): # Записываем статус - успех if not self.setDateAndStatusToConfig(\ sectionPwd, "success", strCurrentTime, txtConfig): return False else: # Записываем статус - ошибка self.setDateAndStatusToConfig(sectionPwd, "error", strCurrentTime, txtConfig) return False else: if set(varsPwdDict.keys()) == set(["date", "status"]): supportSections.append(",".join(sectionPwd)) # Упаковка профиля пользователя if flagRepl and varsPackDict: # Если run=on выполняем команду if varsPackDict.get("run") == "on": # Дата новее которой файлы помещаются в архив strArchDate = varsPackDict.get("arch_date") # Текущее время на клинтском компьютере strCurrentTime = varsPackDict.get("curr_time") if strArchDate and strCurrentTime: # Создаем инкрементный архив if not self.packUserProfile(dirLogOut, strArchDate, strCurrentTime, txtConfig): return False # Удаление секций которые не можем отработать # и секции для создания архива профиля пользователя sections = txtConfig.getAllSectionNames() if supportSections: sections = list(set(sections)-set(["command"])) sections = set(sections)-set(supportSections) delSections = map(lambda x: x.split(","), sections) for delSect in delSections: txtConfig.delArea(delSect) # Если включена репликация и нет команды на упаковку # профиля пользователя if flagRepl and not varsPackDict: # Запись пользователя в Worked ветку LDAP if not setWorkedUser(userName, dirLogOut, profileDir): return False self.printSUCCESS(_("User %s logout")%userName) return True def execServer(self, options, logObj=False): """Выполняется при монтировании и отмонтировании пользовательской директории """ def printErrMessages(errMessages, verboseMode, logObj): """Печать и запись в лог-файл сообщений о ошибках""" if errMessages: if verboseMode: for errMess in errMessages: self.printERROR(errMess) if logObj: for errMess in errMessages: logObj.writeError(errMess) return False def printSuccessMessages(messages, verboseMode, logObj): """Печать и запись в лог-файл сообщений о успехе""" if verboseMode: for mess in messages: self.printSUCCESS(mess) if logObj: for mess in messages: logObj.writeSuccess(mess) return True def redefinePrintMethods(messages, errMessages): """Переопределение методов печати успешных сообщений и ошибок""" prnErr = cl_utils2.cl_smartcon.printERROR cl_utils2.cl_smartcon.printERROR=lambda *x: errMessages.append(x[1]) prnSucces = cl_utils2.cl_smartcon.printSUCCESS cl_utils2.cl_smartcon.printSUCCESS=lambda *x: messages.append(x[1]) return prnSucces, prnErr def restorePrintMethods(prnSucces, prnErr): """Восстанавление методов печати успешных сообщений и ошибок""" cl_utils2.cl_smartcon.printERROR = prnErr cl_utils2.cl_smartcon.printSUCCESS = prnSucces # Сообщения о успехе messages = [] # Сообщения о ошибках errMessages = [] # Опция выключает вывод cообщений на экран verboseMode = True if options.has_key('s'): verboseMode = False login = "" logout = "" makeDir = "" isLogin = options.has_key('login') isLogout = options.has_key('logout') isMakeDir = options.has_key('makedir') dictOpt = {"login":isLogin, "logout":isLogout, "makedir":isMakeDir} firstOpt = filter(lambda x: x[1] ,dictOpt.items()) lenOpt = len(firstOpt) if lenOpt == 1: if isLogin: # Вход пользователя login = options['login'] elif isLogout: # Выход пользователя logout = options['logout'] elif isMakeDir: # Создание директорий для пользователя makeDir = options['makedir'] elif lenOpt == 0: errMessages.append(\ _("command line option '--login' or '--logout' or '--makedir' is \ not set")) return printErrMessages(errMessages, verboseMode, logObj) else: errMessages.append(\ _("command line option '--login' and '--logout' and '--makedir' is \ incompatible")) return printErrMessages(errMessages, verboseMode, logObj) # Создаем переменные шаблонов self.createClVars() # Проверка на установку сервиса LDAP if self.clVars.Get("sr_ldap_set") != "on": errMessages.append(_("LDAP service not setuped")) return printErrMessages(errMessages, verboseMode, logObj) # Проверка на установку samba if self.clVars.Get("sr_samba_set") != "on": errMessages.append(_("Samba service not setuped")) return printErrMessages(errMessages, verboseMode, logObj) # включена или нет репликация flagRepl = False if self.clVars.Get("ld_repl_set") == "on": flagRepl = True if login or makeDir: # Переопределение печати успешных сообщений и ошибок prnSucces, prnErr = redefinePrintMethods(messages, errMessages) # Вход пользователя в сеанс flagMakeDir = False if login: userName = login elif makeDir: userName = makeDir flagMakeDir = True if self.execLoginUser(userName, flagRepl, flagMakeDir): # Восстановление печати успешных сообщений и ошибок restorePrintMethods(prnSucces, prnErr) return printSuccessMessages(messages, verboseMode, logObj) # Восстановление печати успешных сообщений и ошибок restorePrintMethods(prnSucces, prnErr) return printErrMessages(errMessages, verboseMode, logObj) elif logout: # Переопределение печати успешных сообщений и ошибок prnSucces, prnErr = redefinePrintMethods(messages, errMessages) userName = logout # Выход пользователя из сеанса if self.execLogoutUser(userName, flagRepl): # Восстановление печати успешных сообщений и ошибок restorePrintMethods(prnSucces, prnErr) return printSuccessMessages(messages, verboseMode, logObj) # Восстановление печати успешных сообщений и ошибок restorePrintMethods(prnSucces, prnErr) return printErrMessages(errMessages, verboseMode, logObj) def setDateAndStatusToConfig(self, section, status, strDate, objConfig): """Устанавливает для секции текущюю дату и статус""" def printErrMessages(error): """Печать сообщений о ошибках""" errors = error.splitlines() for err in errors: self.printERROR(err) data = {"date":strDate, "status":status} # Удаляем область из конфигурационного файла objConfig.delArea(section) error = objConfig.getError() if error: printErrMessages(error) return False objConfig.setVar(section, data) error = objConfig.getError() if error: printErrMessages(error) return False return True def changeUserPassword(self, userName, varsDict, confFile, strTime): """Изменение пароля пользователя при помощи конфигурационного файла .calculate.env в домашней директории пользователя """ varsData = ("unix_hash", "samba_lm_hash", "samba_nt_hash", "samba_nt_hash_old") if not set(varsData)<=set(varsDict.keys()): notFoundVars = set(varsData) - set(varsDict.keys()) if len(notFoundVars) 2.4)")%openLdapVesion) return False return True @adminConnectLdap def getUsersMail(self): """Находит пользователей в Mail сервисе Вывод список [(имя пользователя, [почтовые адреса пользователя])...)] """ # Проверим установлен ли сервис Mail if not self.isServiceSetup("mail"): return False # ищем пользователей в ветке Mail resSearch = self.searchLdapDN("*", self.servMailObj.relUsersDN, "mailAlternateAddress", ["uid","mailAlternateAddress"]) if not resSearch: return False listUserMail = [] for i in resSearch: listUserMail.append((i[0][1]["uid"][0], i[0][1]["mailAlternateAddress"])) return listUserMail @adminConnectLdap def getGroupsMail(self): """Находит группы в Mail сервисе Вывод список [(группа, [почтовые адреса группы],[невидимые хосты])...)] """ # Проверим установлен ли сервис Mail if not self.isServiceSetup("mail"): return False # ищем группы в ветке Mail resSearch = self.searchLdapDN("*", self.servMailObj.relGroupsDN, "mailAlternateAddress", ["cn","mailAlternateAddress", "filtersender"]) if not resSearch: return False listGroupMail = [] for i in resSearch: if i[0][1].has_key('filtersender'): listGroupMail.append((i[0][1]["cn"][0], i[0][1]["mailAlternateAddress"], i[0][1]["filtersender"])) else: listGroupMail.append((i[0][1]["cn"][0], i[0][1]["mailAlternateAddress"],[])) return listGroupMail def setupReplServer(self, options, service): """Начальная настройка репликации""" # Cоздаем объект переменные self.createClVars() # Определяем поддерживает ли openldap репликацию if not self.supportReplOpenldap(self.clVars): return False if options.has_key('off'): if self.clVars.Get("ld_repl_set") == "off": self.printWARNING(_("Replication off for all services")) return True elif service == "unix" and\ self.clVars.Get("ld_repl_unix_set") == "off": self.printWARNING(_("Replication off for service %s")%"Unix") return True elif service == "samba" and\ self.clVars.Get("ld_repl_samba_set") == "off": self.printWARNING(_("Replication off for service %s")%"Samba") return True elif service == "mail" and\ self.clVars.Get("ld_repl_mail_set") == "off": self.printWARNING(_("Replication off for service %s")%"Mail") return True self.printWARNING(_("Undo can be achieved by executing a command")) self.printWARNING(_("when the backup was created on this server \ 'cl-rebuild',")) self.printWARNING(_("if taken from another server \ 'cl-rebuild --repl'")) bFile = self.servLdapObj.getArchFile() if not bFile: return Falses archFileTime = time.localtime(os.stat(bFile)[stat.ST_MTIME]) timeFile = datetime.datetime(archFileTime[0],archFileTime[1], archFileTime[2],archFileTime[3], archFileTime[4],archFileTime[5]) localTime = time.localtime() timeLocal = datetime.datetime(localTime[0],localTime[1], localTime[2],localTime[3], localTime[4],localTime[5]) if timeLocal < timeFile: self.printERROR(_("Incorrect system time or time create \ file %s")%bFile) return False deltaTime = timeLocal - timeFile if deltaTime.days == 0: deltaSec = deltaTime.seconds dHours = int(deltaSec/3600) dMinutes = int((deltaSec - dHours*3600)/60) dSeconds = deltaSec - dHours*3600 - dMinutes*60 hours = _("hours") minutes = _("minutes") seconds = _("seconds") if dHours: timeBackup = "%s %s %s %s %s %s"%\ (dHours,hours,dMinutes,minutes,dSeconds,seconds) elif dMinutes: timeBackup = "%s %s %s %s"%(dMinutes,minutes,dSeconds,\ seconds) elif dSeconds: timeBackup = "%s %s"%(dSeconds,seconds) self.printWARNING(_("The backup file is created %s ago")\ %timeBackup) else: self.printWARNING(_("The backup file is created %s days ago")\ %deltaTime.days) self.printWARNING(_("If the backup is obsolete, use cl-backup-server.")) messDialog = \ _("If you are ready to continue executing the program")+", "+\ _("input 'yes'") +", "+ _("if not 'no'") if not self.dialogYesNo(messDialog): return True # Удаляем переменную из /var/calculate.calculate.env self.clVars.Delete("ld_repl_ids","local","server") # Cоздаем объект переменные self.createClVars() # Записываем что репликация отключена self.clVars.Write("ld_repl_set", "off") # Включаем репликацию self.clVars.Set("ld_repl_set", "on") if not options.has_key('off') and\ (not options.has_key('r') or not options['r']): self.printERROR(\ _("Not specified replication servers \ (command line option '-r')")) return False if options.has_key('off') and options.has_key('r'): self.printERROR(\ _("You can not use the option to '--off', \ together with option '-r'")) return False replServers = [] if options.has_key('r'): replServers = options['r'].split(',') # Преобразуем короткие имена в длинные hostName = self.clVars.Get('os_net_hostname') domain = self.clVars.Get('os_net_domain') replServers = self.shortToFullName(replServers, domain) fullHostName = "%s.%s"%(hostName,domain) # Удаляем похожие сервера и текущий сервер из списка replServers = self.genReplServers(replServers, hostName, fullHostName) # Если серверы отсуствуют - ошибка if not replServers: self.printERROR(\ _("Not a valid list of servers replication")) return False # Добавляем текущий сервер в серверы репликации replServers.insert(0,fullHostName) # В случае если сервер установлен if self.clVars.Get("sr_ldap_set") != "on": self.printERROR(\ _("Set Replication error, LDAP service not setuped")) return False if service == "unix": if self.clVars.Get("sr_unix_set") != "on": self.printERROR(\ _("Set Replication error, Unix service not setuped")) return False if options.has_key('r'): replSambaServers = self.clVars.Get("ld_repl_samba_servers") replMailServers = self.clVars.Get("ld_repl_mail_servers") dictServers = {"samba":replSambaServers, "mail":replMailServers, "unix":",".join(replServers)} listServersRepl = map(lambda x: (x[0],set(x[1].split(","))), filter(lambda x: x[1], dictServers.items())) # Все серверы репликации replAllServers = list(reduce(lambda x,y: ('',x[1]|y[1]), listServersRepl,("",set()))[1]) # Серверы репликации для ветки Unix replUnixServers = list(reduce(lambda x,y: ('',x[1]|y[1]), filter(lambda x: x[0] in ['samba','unix'], listServersRepl),("",set()))[1]) # Устанавливаем переменную серверы репл. для Unix сервиса self.clVars.Set("ld_repl_unix_servers", ",".join(replUnixServers),True) # Устанавливаем переменную серверы репл. для всех сервисов self.clVars.Set("ld_repl_servers", ",".join(replAllServers),True) elif options.has_key('off'): # Выключаем репликацию для сервисов Samba и Mail if self.clVars.Get("ld_repl_mail_set") == "on" and\ self.clVars.Get("ld_repl_mail_servers"): self.clVars.Set("ld_repl_set", "on", True) # Устанавливаем переменную серверы репл. для всех сервисов self.clVars.Set("ld_repl_servers", self.clVars.Get("ld_repl_mail_servers"),True) else: self.clVars.Set("ld_repl_set", "off", True) self.clVars.Delete("ld_repl_mail_servers","local","server") self.clVars.Set("ld_repl_samba_set", "off", True) self.clVars.Set("ld_repl_unix_set", "off", True) self.clVars.Set("ld_repl_unix_servers", "", True) self.clVars.Set("ld_repl_samba_servers", "", True) self.clVars.Delete("ld_repl_unix_servers","local","server") self.clVars.Delete("ld_repl_samba_servers","local","server") elif service == "samba": if self.clVars.Get("sr_samba_set") != "on": self.printERROR(\ _("Set Replication error, Samba service not setuped")) return False replUnixServers = self.clVars.Get("ld_repl_unix_servers") if replUnixServers: replUnixServers = replUnixServers.split(",") if options.has_key('off'): # Очищаем cерверы репликации Samba self.clVars.Set("ld_repl_samba_servers", "", True) self.clVars.Delete("ld_repl_samba_servers","local","server") replServers = [] replSambaServers = self.clVars.Get("ld_repl_samba_servers") if replSambaServers: replSambaServers = replSambaServers.split(",") replMailServers = self.clVars.Get("ld_repl_mail_servers") # Находим разницу между серверами Samba и Unix diffReplServers = list(set(replSambaServers)^set(replUnixServers)) dictServers = {"samba":",".join(replServers), "mail":replMailServers, "unix":",".join(diffReplServers)} listServersRepl = map(lambda x: (x[0],set(x[1].split(","))), filter(lambda x: x[1], dictServers.items())) # Все серверы репликации replAllServers = list(reduce(lambda x,y: ('',x[1]|y[1]), listServersRepl,("",set()))[1]) # Серверы репликации для ветки Unix replUnixServers = list(reduce(lambda x,y: ('',x[1]|y[1]), filter(lambda x: x[0] in ['samba','unix'], listServersRepl),("",set()))[1]) # Серверы репликации для ветки Samba replSambaServers = list(reduce(lambda x,y: ('',x[1]|y[1]), filter(lambda x: x[0] in ['samba'], listServersRepl),("",set()))[1]) # Устанавливаем переменную серверы репл. для Samba сервиса self.clVars.Set("ld_repl_samba_servers", ",".join(replSambaServers),True) # Устанавливаем переменную серверы репл. для Unix сервиса self.clVars.Set("ld_repl_unix_servers", ",".join(replUnixServers),True) # Устанавливаем переменную серверы репл. для всех сервисов self.clVars.Set("ld_repl_servers", ",".join(replAllServers),True) if not self.clVars.Get("ld_repl_id"): # Вылючаем репликацию self.clVars.Set("ld_repl_set", "off") elif service == "mail": if self.clVars.Get("sr_mail_set") != "on": self.printERROR(\ _("Set Replication error, Mail service not setuped")) return False replUnixServers = self.clVars.Get("ld_repl_unix_servers") if options.has_key('off'): # Очищаем cерверы репликации Mail self.clVars.Set("ld_repl_mail_servers", "", True) self.clVars.Delete("ld_repl_mail_servers","local","server") replServers = [] replSambaServers = self.clVars.Get("ld_repl_samba_servers") dictServers = {"samba":replSambaServers, "mail":",".join(replServers), "unix":replUnixServers} listServersRepl = map(lambda x: (x[0],set(x[1].split(","))), filter(lambda x: x[1], dictServers.items())) # Все серверы репликации replAllServers = list(reduce(lambda x,y: ('',x[1]|y[1]), listServersRepl,("",set()))[1]) # Серверы репликации для ветки Mail replMailServers = list(reduce(lambda x,y: ('',x[1]|y[1]), filter(lambda x: x[0] in ['mail'], listServersRepl),("",set()))[1]) # Устанавливаем переменную серверы репл. для Mail сервиса self.clVars.Set("ld_repl_mail_servers", ",".join(replMailServers),True) # Устанавливаем переменную серверы репл. для всех сервисов self.clVars.Set("ld_repl_servers", ",".join(replAllServers),True) if not self.clVars.Get("ld_repl_id"): # Вылючаем репликацию self.clVars.Set("ld_repl_set", "off") else: self.printERROR(\ _("incorrect service '%s' in method setupReplServer")%service) return False # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False #Cоединение с Ldap (администратор) if not shareLdap.getLdapObjInFile(self): return False if options.has_key('r'): # Проверяем существует ли id текущего сервера if not self.clVars.Get("ld_repl_id"): self.printERROR(_("Not found 'serverID' this server")) self.printERROR(_("variable 'ld_repl_id' empty")) return False # Делаем update cервиса Samba в случае опции off и не показываем # реплицируемые серверы if service == "unix" and self.clVars.Get("sr_samba_set") == "on" and\ options.has_key('off'): if not self.servLdapObj.updateServer({},"samba",self.clVars, [],False): return False # Делаем update сервиса если нет ветки репликации она создается if not self.servLdapObj.updateServer({},service,self.clVars): return False if self.clVars.Get("ld_repl_set") != "on": # Удаляем переменные self.deleteVars() self.printOK(_("Replication off for all services") + " ...") return True #запишем переменные для сервера # в /etc/calculate.env self.clVars.Write("ld_repl_pw", self.clVars.Get("ld_repl_pw"),True) # в /var/calculate/calculate.env if service == "unix": self.clVars.Write("ld_repl_unix_servers", self.clVars.Get("ld_repl_unix_servers"), True,"local") elif service == "samba": self.clVars.Write("ld_repl_unix_servers", self.clVars.Get("ld_repl_unix_servers"), True,"local") smbServers = self.clVars.Get("ld_repl_samba_servers") if smbServers: self.clVars.Write("ld_repl_samba_servers", smbServers, True, "local") elif service == "mail": # Cчитаем почтовых пользователей и заполним ветку алиасов # Переподсоединяемся к LDAP self.ldapObj = False # Получаем почтовых пользователей usersMail = self.getUsersMail() # Получаем почтовые группы groupsMail = self.getGroupsMail() # объединяет usersMail и groupsMail usersAndGroupsMail = map(lambda x: (len(x)==2 and\ (x[0],x[1],[])) or x, reduce(lambda x, y: x+y,\ map(lambda x: x or [], [usersMail,groupsMail]),[])) if usersAndGroupsMail: flagError = False for name, mails, hosts in usersAndGroupsMail: if self.searchMailAlias(name): if not self.modReplMailAlias(name, mails, hosts): flagError = True break else: if not self.addReplMailAlias(name, mails, hosts): flagError = True break if flagError: self.printERROR(_("Can not set replication mail alias,") +\ " " + _("for name %s")%name + " " +\ "(%s)"%", ".join(mails)) return False mailServers = self.clVars.Get("ld_repl_mail_servers") if mailServers: self.clVars.Write("ld_repl_mail_servers", mailServers, True, "local") # Серверы репликации self.clVars.Write("ld_repl_servers", self.clVars.Get("ld_repl_servers"), True,"local") # Id серверов репликации self.clVars.Write("ld_repl_ids", self.clVars.Get("ld_repl_ids"), True,"local") ldapParser = iniLdapParser() ldapParser.setVar("replication", {"DN":self.clVars.Get("ld_repl_dn"), "PASS":self.clVars.Get("ld_repl_pw")}) #Записываем что репликация включена self.clVars.Write("ld_repl_set", "on") self.printOK(_("Replication setuped") + " ...") return True class cl_info(cl_utils2.cl_smartcon, prnServ): """Класс для вывода информации""" def getInfoServer(self, options, service): """Выводит на печать информацию""" strService = self.printNameService(service) # Информация сервиса DHCP # Информация о всех сетях DHCP if service == "dhcp" and options.has_key("n"): dhcpObj = dncpTxt() dataNets = dhcpObj.getDataInAllSubnet() dataList = [] for net, data in dataNets: dataTmp = [] if data.has_key('net'): dataTmp.append(data['net'][0]) if data.has_key('mask'): dataTmp.append(data['mask'][0]) if len(dataTmp) == 2: dataList.append(["%s/%s"%(dataTmp[0],\ dhcpObj.convertNetMask(dataTmp[1]))]) # Формирование строки для отчета title=_("Information about the DHCP networks in %s")\ %dhcpObj.nameConfigFile headerList = [_("DHCP networks")] repObj = report(title, headerList, dataList) repObj.printReport() return True # Информация о сети DHCP if service == "dhcp" and options.has_key("N"): # ip сети и сетевая маска /24 net = options["N"] # cоздаем объект DHCP servDhcpObj = servDhcp() # проверка правильности сети network, spl, netmask = net.rpartition("/") if not servDhcpObj.isCorrectStringNet(net): self.printERROR(_('Incorrect network %s')%net) self.printWARNING(_("Example network") + " :") self.printWARNING('"-N 192.168.0.0/24"') return False # Проверка сущестовования сети в конфигурационном файле if not servDhcpObj.isExistingNet(net): return False dhcpObj = dncpTxt() dataNets = dhcpObj.getDataInAllSubnet() dataList = [] for netTmp, data in dataNets: if network == netTmp: if "net" in data.keys(): value = data["net"][0] dataList.append(["Network", value]) if "mask" in data.keys(): value = data["mask"][0] dataList.append(["Network mask", value]) for key in data.keys(): if key == "net" or key == "mask": continue keyInsert = key.replace("option", "") keyInsert = keyInsert.replace("routers", "router") keyInsert = keyInsert.replace("-", " ") if key[:6] == "option": keyInsert = "Client " + keyInsert keyInsert = keyInsert.capitalize() value = "" if key == "range": keyInsert = "Dynamic ip range" if data[key]: value = " ".join(data[key]) elif keyInsert == "Client domain name": if data[key]: value = " ".join(data[key]).replace('"','') elif keyInsert == "Client domain name servers": if data[key]: value = data[key][0].replace(',',' ') else: if data[key]: value = data[key][0] if value: dataList.append([keyInsert, value]) # Формирование строки для отчета title=_("Information about the DHCP network %s") %net +\ " "+_("in %s") %dhcpObj.nameConfigFile headerList = [_("Field"), _("Value")] repObj = report(title, headerList, dataList) repObj.printReport() return True # Информация о статическом носте DHCP if service == "dhcp" and options.has_key("H"): hostname = options["H"] # Проверка правильности названия хоста if '.' in hostname: self.printERROR(_('Command line option "-H %s" incorrectly')\ %hostname) self.printWARNING(_("Example") + " :") self.printWARNING('"-H computer"') return False dhcpObj = dncpTxt() dataHosts = dhcpObj.getDataInAllHost() dataList = [] for hostTmp, data in dataHosts: if hostname == hostTmp: if "host" in data.keys(): keyInsert = "Host" value = " ".join(data['host']) if value: dataList.append([keyInsert, value]) for key in data.keys(): if key == "host": continue keyInsert = key.replace("-", " ") if keyInsert == "hardwareethernet": keyInsert = "Mac address" keyInsert = keyInsert.capitalize() value = "" if data[key]: value = " ".join(data[key]) if value: dataList.append([keyInsert, value]) # Формирование строки для отчета title=_("Information about the DHCP static host %s") %hostname +\ " "+_("in %s") %dhcpObj.nameConfigFile headerList = [_("Field"), _("Value")] repObj = report(title, headerList, dataList) repObj.printReport() return True # Информация о всех статических хостах DHCP if service == "dhcp" and options.has_key("hosts"): dhcpObj = dncpTxt() dataHosts = dhcpObj.getDataInAllHost() dataList = [] for hostname, data in dataHosts: ip = "" if data.has_key("fixed-address"): if data["fixed-address"]: ip = data["fixed-address"][0] dataList.append([hostname,ip]) # Формирование строки для отчета title=_("Information about the all DHCP static hosts in %s")\ %dhcpObj.nameConfigFile headerList = [_("Static hosts"), _("IP address")] repObj = report(title, headerList, dataList) repObj.printReport() return True # Информация о DNS if service == "dns" and options.has_key("z") or options.has_key("Z") or\ options.has_key("r"): # cоздаем объект DNS servDnsObj = servDns() # Проверим установлен ли сервис dns if not servDnsObj.isServiceSetup("dns"): return False objTxtZone = dnsTxt() # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) # Информация о всех DNS зонах if service == "dns" and options.has_key("z"): # Зоны в файле namesZonesFile = objTxtZone.getAllNamesZones() if namesZonesFile == False: return False # Зоны в LDAP namesZonesLDAP = servDnsObj.searchAllZonesInLDAP() # Подчиненные зоны slaveZones = list(set(namesZonesFile)-set(namesZonesLDAP)) # Обратные зоны if namesZonesLDAP: namesZonesLDAP.sort() reverseZones = filter(lambda x: '.in-addr.arpa' in x,\ namesZonesLDAP) # Прямые зоны forwardZones = filter(lambda x: not '.in-addr.arpa' in x,\ namesZonesLDAP) # Формирование строки для отчета title=_("Information about the master DNS zones in LDAP") headerList = [_("DNS zone"), _("Domain (forward zone)"), _("Network (reverse zone)")] # Получение домена getDomain = lambda x: not '.in-addr.arpa' in x and x or "" # Получение сети getNet = lambda x: ".".join(map(lambda x:x,\ reversed('.in-addr.arpa' in x and ["0/24"] +\ x.rpartition(".in-addr.arpa")[0].split(".") or []))) dataList = map(lambda x:\ [x, getDomain(x), getNet(x)],\ forwardZones + reverseZones) repObj = report(title, headerList, dataList) repObj.printReport() if slaveZones: # Получаем данные для подчиненной зоны slaveIPs = [] slaveZones.sort() for slZone in slaveZones: flagAddIPs = False xmlArea = objTxtZone.getXMLZoneToName(slZone)[0] xmlNodes = xpath.Evaluate("child::field[child::name='%s']"\ %("masters"), xmlArea) if xmlNodes: masterIPNode = xmlNodes[0] xmlNodes = xpath.Evaluate( "child::value", masterIPNode) ips = map(lambda x: x.firstChild.nodeValue.strip(),\ xmlNodes) flagAddIPs = True slaveIPs.append(",".join(ips)) if not flagAddIPs: slaveIPs.append("") reverseZones = filter(lambda x: '.in-addr.arpa' in x,\ slaveZones) # Прямые зоны forwardZones = filter(lambda x: not '.in-addr.arpa' in x,\ slaveZones) # Формирование строки для отчета title=_("Information about the slave DNS zones in \ /etc/bind/named.conf") headerList = [_("DNS zone"),_("IP master DNS servers")] dataList = map(lambda x: [x], forwardZones + reverseZones) dataList = map(lambda x: dataList[x]+[slaveIPs[x]],\ range(len(dataList))) repObj = report(title, headerList, dataList) print "" repObj.printReport() return True # Информация о DNS зоне if service == "dns" and options.has_key("Z"): zoneName = options["Z"] if not zoneName: self.printERROR(_('Incorrect zone name')) return False # Проверка на прямую зону forwardZone = servDnsObj.isForwardName(zoneName) # Обратная зона if not forwardZone: network, spl, netmask = zoneName.rpartition("/") if not netmask == "24" or \ not servDnsObj.isCorrectStringNet(zoneName): self.printERROR(_('Incorrect network %s for reverse zone')\ %zoneName) self.printWARNING(_("Example network for reverse zone") +\ " :") self.printWARNING('"192.168.0.0/24"') return False dataIP = servDnsObj.getDomainAndZoneFromIP(network) if not dataIP: self.printERROR(_("IP address %s incorrectly")%network) return False hostNameTmp, domainNameTmp, zoneName = dataIP # Ищем мастер зону в LDAP if not servDnsObj.searchZoneInLDAP(zoneName): # Зоны в файле namesZonesFile = objTxtZone.getAllNamesZones() if namesZonesFile == False: return False # Зоны в LDAP namesZonesLDAP = servDnsObj.searchAllZonesInLDAP() # Подчиненные зоны slaveZones = list(set(namesZonesFile)-set(namesZonesLDAP)) # Если подчиненная зона if not zoneName in slaveZones: self.printERROR(_("Can not found master zone %s in LDAP")\ %zoneName) return False # ip мастер серверов в подчиненной зоне ipMasterServers = [] xmlArea = objTxtZone.getXMLZoneToName(zoneName)[0] xmlNodes = xpath.Evaluate("child::field[child::name='%s']"\ %("masters"), xmlArea) if xmlNodes: masterIPNode = xmlNodes[0] xmlNodes = xpath.Evaluate( "child::value", masterIPNode) ipMasterServers = map(lambda x:\ x.firstChild.nodeValue.strip(),\ xmlNodes) if not ipMasterServers: self.printERROR(_("The program does not support information \ for %s DNS zone")%zoneName) return False title=_("Information about slave DNS zone %s in \ /etc/bind/named.conf") %zoneName headerList = [_("Field"), _("Value")] flagF = True dataList = [] for ipMS in ipMasterServers: if flagF: dataList.append([_("IP master DNS servers"), ipMS]) flagF = False else: dataList.append(["", ipMS]) repObj = report(title, headerList, dataList) repObj.printReport() return True # Получение данных зоны из LDAP zoneData = servDnsObj.searchAllDomainNamesInLDAP("@.%s"%zoneName) if not zoneData: self.printERROR(_("Can not found SOA-record in zone %s")\ %zoneName) return False soaRecord = zoneData[0][0][1]['sOARecord'][0] # Все авторитативные сервера зоны nSRecords = zoneData[0][0][1]['nSRecord'] mXRecords = [] if zoneData[0][0][1].has_key('mXRecord'): mXRecords = zoneData[0][0][1]['mXRecord'] aRecords = [] if zoneData[0][0][1].has_key('aRecord'): aRecords = zoneData[0][0][1]['aRecord'] soaData = map(lambda x: delDot(x), soaRecord.split(" ")) if len(soaData)!=7: self.printERROR(_("Incorrect SOA-record in DNS zone %s")\ %zoneName) return False # Авторитативный сервер nameServer = soaData[0] # Почтовый адрес администратора зоны splEmail = soaData[1].partition(".") email = "%s@%s"%(splEmail[0], delDot(splEmail[2])) # Серийный номер зоны serialNumber = soaData[2] # refresh - интервал времени для обновления зоны refresh = soaData[3] # update - интервал времени после неудачного обновления зоны update = soaData[4] # expiry - интервал времени устаревания данных зоны expiry = soaData[5] # minimum - интервал времени хранения данных неудачных запросов minimum = soaData[6] # Формирование строки для отчета title=_("Information about master DNS zone %s")%zoneName headerList = [_("Field"), _("Value")] dataList = [[_("Zone name"), zoneName], [_("Master autoritative server"), nameServer], [_("Email administrator"), email], [_("Serial number"), serialNumber], [_("Refresh"), refresh], [_("Update"), update], [_("Expiry"), expiry], [_("Minimum"), minimum]] if mXRecords: map(lambda x:dataList.insert(2,["",x]) ,reversed(mXRecords[1:])) dataList.insert(2,[_("MX-record"), mXRecords[0]]) if aRecords: map(lambda x:dataList.insert(2,["",x]) ,reversed(aRecords[1:])) dataList.insert(2,[_("A-record"), aRecords[0]]) if nSRecords: map(lambda x:dataList.insert(2,["",x]), reversed(nSRecords[1:])) dataList.insert(2,[_("NS-record"), nSRecords[0]]) repObj = report(title, headerList, dataList) repObj.printReport() recordsSearch = servDnsObj.searchAllRecordInZone(zoneName) if recordsSearch: # Если прямая зона if forwardZone: dataAList = [] dataCNList = [] dataMXList = [] for record in recordsSearch: domainName = "%s.%s"\ %(record[0][1]["relativeDomainName"][0],\ zoneName) if record[0][1].has_key("aRecord"): dataAList.append([domainName, record[0][1]["aRecord"][0]]) if record[0][1].has_key("mXRecord"): flagFirst = True flagError = False for mxData in record[0][1]["mXRecord"]: mxDataSpl = mxData.split(" ") if len(mxDataSpl) != 2: flagError = True break prioritet, mxDomain = mxDataSpl if flagFirst: dataMXList.append([domainName, prioritet, delDot(mxDomain)]) flagFirst = False else: dataMXList.append(["", prioritet, delDot(mxDomain)]) if flagError: self.printERROR(\ _("Incorrect MX-records in A-record %s")\ %domainName) return False elif record[0][1].has_key("cNAMERecord"): dataCNList.append([domainName, delDot(record[0][1]["cNAMERecord"][0])]) allDataList = [dataAList, dataCNList,dataMXList] allRecordList = ["A","CNAME","MX"] allHeaderList = [(_("Domain"), "ip"), (_("Domain"), _("CNAME Domain")), (_("Domain"), _("Priority"),\ _("MX Domain"))] for i in range(len(allRecordList)): if allDataList[i]: title=_("Information about %s-records")\ %allRecordList[i] + " " +\ _("in master DNS zone %s")%zoneName headerList = allHeaderList[i] dataList = allDataList[i] repObj = report(title, headerList, dataList) print "" repObj.printReport() # Если обратная зона else: dataPTRList = [] # Получение из названия зоны cтроки из 3-х частей IP getThreeOctetsIP = lambda x: ".".join(map(lambda x:x,\ reversed('.in-addr.arpa' in x and\ x.rpartition(".in-addr.arpa")[0].split(".") or []))) threeOctetsIP = getThreeOctetsIP(zoneName) if not threeOctetsIP: self.printERROR(_("Incorrect zone name %s")%zoneName) return False for record in recordsSearch: if record[0][1].has_key("pTRRecord"): IP = "%s.%s"%(threeOctetsIP,\ record[0][1]["relativeDomainName"][0]) domainName = delDot(record[0][1]["pTRRecord"][0]) dataPTRList.append([IP, domainName]) if dataPTRList: title=_("Information about %s-records")\ %"PTR" + " " +\ _("in master DNS zone %s")%zoneName headerList = ("ip", _("Domain")) dataList = dataPTRList repObj = report(title, headerList, dataList) print "" repObj.printReport() return True # Информация о DNS записи if service == "dns" and options.has_key("r"): hostOrIP = options["r"] # Флаг True - hostOrIP является хостом hostInForwardZone = servDnsObj.isForwardName(hostOrIP) domainName = "" domainNamePTR = "" # Найденные данные о записи dataRecords = [] headerList = [_("Field"), _("Value")] dataList = [] # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) # hostOrIP является именем хоста if hostInForwardZone: domainName = delDot(hostOrIP.lower()) # Имя хоста, имя зоны hostName, spl, zoneName = domainName.partition(".") if not zoneName or "@" in hostName: self.printERROR(_("Domain name %s incorrectly")%domainName) return False dataRecords = servDnsObj.searchAllDomainNamesInLDAP(domainName) if not dataRecords: self.printERROR(_("Record %s not exists in LDAP")\ %domainName) return False flagF = True for record in dataRecords: dataList.append([_("Domain name"), domainName]) if record[0][1].has_key("aRecord"): dataList.append([_("A-record"),\ record[0][1]["aRecord"][0]]) if record[0][1].has_key("mXRecord"): flagFirst = True flagError = False for mxData in record[0][1]["mXRecord"]: mxDataSpl = mxData.split(" ") if len(mxDataSpl) != 2: flagError = True break if flagFirst: dataList.append([_("MX-record") ,mxData]) flagFirst = False else: dataList.append(["", mxData]) if flagError: self.printERROR(\ _("Incorrect MX-records in A-record %s")\ %domainName) return False typeRecord = "A" elif record[0][1].has_key("cNAMERecord"): dataList.append([_("CNAME-record"),\ record[0][1]["cNAMERecord"][0]]) typeRecord = "CNAME" title=_("Information about %s-record")\ %typeRecord + " " +\ _("in master DNS zone %s")%zoneName repObj = report(title, headerList, dataList) if flagF: flagF = False else: print "" repObj.printReport() # hostOrIP является ip else: if "," in hostOrIP or \ not servDnsObj.isCorrectStringNet(hostOrIP, False): self.printERROR(_("IP address %s incorrectly")%hostOrIP) return False ip = hostOrIP dataIP = servDnsObj.getDomainAndZoneFromIP(ip) if not dataIP: self.printERROR(_("IP address %s incorrectly")%ip) return False hostNamePTR, domainNamePTR, zoneNamePTR = dataIP dataRecords=servDnsObj.searchAllDomainNamesInLDAP(domainNamePTR) if not dataRecords: self.printERROR(_("Record %s not exists in LDAP")\ %domainNamePTR) return False flagF = True typeRecord = "Unknown" for record in dataRecords: dataList.append(["ip", ip]) if record[0][1].has_key("pTRRecord"): domainNameDot = record[0][1]["pTRRecord"][0] dataList.append([_("PTR-record"), domainNameDot]) typeRecord = "PTR" title=_("Information about %s-record")\ %typeRecord + " " +\ _("in master DNS zone %s")%zoneNamePTR repObj = report(title, headerList, dataList) if flagF: flagF = False else: print "" repObj.printReport() return True # Информация о компьютере if options.has_key("M"): machineName = options["M"] data = self.getMachine(machineName, service) if not data: return False headerList, dataList = data title=_("Information about machine %s") %machineName + " " +\ _("for service %s") %strService # Информация о пользователе elif options.has_key("U"): userName = options["U"] data = self.getUser(userName, service) if not data: return False headerList, dataList = data title=_("Information about user %s") %userName + " " +\ _("for service %s") %strService # Информация о группе elif options.has_key("G"): groupName = options["G"] data = self.getGroup(groupName, service) if not data: return False headerList, dataList = data title=_("Information about group %s") %groupName + " " +\ _("for service %s") %strService # Информация о компьютерах elif options.has_key("m"): fields = "short" if options.has_key("full"): fields = "full" data = self.getAllMachines(fields, service) if not data: return False headerList, dataList = data title=_("All machines in LDAP for service %s")%strService # Информация о пользователях elif options.has_key("u"): fields = "short" if options.has_key("full"): fields = "full" data = self.getAllUsers(fields, service) if not data: return False headerList, dataList = data title=_("All users in LDAP for service %s")%strService # Информация о группах elif options.has_key("g"): fields = "short" if options.has_key("full"): fields = "full" data = self.getAllGroups(fields, service) if not data: return False headerList, dataList = data title=_("All groups in LDAP for service %s")%strService if options.has_key("M") or options.has_key("m") or\ options.has_key("U") or options.has_key("G") or\ options.has_key("u") or options.has_key("g"): repObj = report(title, headerList, dataList) repObj.printReport() return True if len(options) == 1 and options.has_key("full"): self.printERROR(_("Can not use a single command line option \ 'full'.")) self.printERROR(_("This option should be used in conjunction \ with another option.")) self.printWARNING(_("Example")) self.printWARNING(" cl-info -u -full %s" %service) return False def getQueryLDAP(self, service, branch, searchAttr, searchStr, retrAttrs=None, returnClVars=False): """Выдает данные из LDAP""" branchData = {'users':'relUsersDN', 'groups':'relGroupsDN', 'computers':'relComputersDN'} if not branchData.has_key(branch): self.printERROR("getQueryLDAP service=%s"%service) self.printERROR(_("ERROR: getQueryLDAP incorrect branch=%s")%branch) return False relAttr = branchData[branch] try: exec ("servObj=serv%s()" %service.capitalize()) except: self.printERROR(\ _("ERROR: getQueryLDAP incorrect service=%s")%service) return False # Если сервис не установлен то ошибка if not servObj.isServiceSetup(service): return False if not servObj.__dict__.has_key(relAttr): self.printERROR("getQueryLDAP service=%s"%service) self.printERROR(_("ERROR: getQueryLDAP incorrect branch=%s")%branch) return False searchRes = servObj.searchLdapDN(searchStr, getattr(servObj, relAttr), searchAttr, retrAttrs) if returnClVars: return (servObj.clVars, searchRes) return searchRes def getMachine(self, machineName, service): """Информация о компьютере""" searchAttr = "uid" machName = machineName.split("$") machName = "".join(machName) machName += "$" searchStr = machName data, delData = self.genDataMachines(service) if not data: self.printERROR(_("Incorrect service %s")\ %self.printNameService(service)) return False headers = [_("Field"),_("Value")] attributes = map(lambda x: x[0], data) retrAttrs = map(lambda x: x[1], data) retClVars=False searchRes = self.getQueryLDAP(service, "computers", searchAttr, searchStr, retrAttrs) if searchRes == False: return False if not searchRes: return (headers , []) data = [] lenRetrAttrs = len(retrAttrs) for info in searchRes: for i in range(lenRetrAttrs): attr = retrAttrs[i] attrName = attributes[i] if attr in info[0][1]: ldapValue = info[0][1][attr] # Изменяем значения аттрибутов для вывода на печать ldapValue[0] = self.modUserAttr(attr, ldapValue[0], service) flagFirst = False for value in ldapValue: if not flagFirst: data.append((attrName, value)) flagFirst = True else: data.append(("", value)) if service == "samba" and attr == "gidNumber": memberGroups = self._getUserMemberGroups(machName, service) attrApp = _("Supplementary groups") if service == "samba": if value: memberGroups.insert(0,value) flagFirst = False for value in memberGroups: if not flagFirst: data.append((attrApp, value)) flagFirst = True else: data.append(("", value)) else: data.append((attrName, _("No"))) return (headers, data) def getGroup(self, groupName, service): """Информация о группе""" searchAttr = "cn" searchStr = groupName data, delData = self.genDataGroups(service) if not data: self.printERROR(_("Incorrect service %s")\ %self.printNameService(service)) return False headers = [_("Field"),_("Value")] attributes = map(lambda x: x[0], data) retrAttrs = map(lambda x: x[1], data) retClVars=False searchRes = self.getQueryLDAP(service, "groups", searchAttr, searchStr, retrAttrs) if searchRes == False: return False if not searchRes: return (headers , []) if service == "proxy": for i in searchRes: memberList = i[0][1]['member'] i[0][1]['member']=map(lambda x: x.partition("=")[2],memberList) if service == "jabber": servObj = servJabber() resMemberSearch = servObj.searchUsersToGroup(groupName) if resMemberSearch: memberUid = [] for dataGroup in resMemberSearch: memberUid.append(dataGroup[0][1]['uid'][0]) for i in searchRes: i[0][1]['memberUid'] = memberUid data.append((_("Member UID"),"memberUid")) attributes = map(lambda x: x[0], data) retrAttrs = map(lambda x: x[1], data) data = [] lenRetrAttrs = len(retrAttrs) # Добавляем первичные группы if service in ("unix", "samba"): memberUid = [] if searchRes[0][0][1].has_key('memberUid'): memberUid = searchRes[0][0][1]['memberUid'] groupId = searchRes[0][0][1]['gidNumber'][0] primaryUids = self.getUnixUidPrimGroup(groupId) memberUid = primaryUids + memberUid uniqueUid = [] # Удаляем одинаковые элементы for uid in memberUid: if not uid in uniqueUid: uniqueUid.append(uid) if uniqueUid: searchRes[0][0][1]['memberUid'] = uniqueUid for info in searchRes: for i in range(lenRetrAttrs): attr = retrAttrs[i] attrName = attributes[i] if attr in info[0][1]: ldapValue = info[0][1][attr] # Изменяем значения аттрибутов для вывода на печать for i in range(len(ldapValue)): ldapValue[i] = self.modGroupAttr(attr, ldapValue[i], service) flagFirst = False for value in ldapValue: if not flagFirst: data.append((attrName, value)) flagFirst = True else: data.append(("", value)) else: data.append((attrName, _("No"))) return (headers, data) def getUser(self, userName, service): """Информация о пользователе""" searchAttr = "uid" searchStr = userName data, delData = self.genDataUsers(service) if not data: self.printERROR(_("Incorrect service %s")\ %self.printNameService(service)) return False headers = [_("Field"), _("Value")] attributes = map(lambda x: x[0], data) retrAttrs = map(lambda x: x[1], data) retClVars=False if service in ["mail", "samba"]: retClVars=True searchRes = self.getQueryLDAP(service, "users", searchAttr, searchStr, retrAttrs, retClVars) if searchRes == False: return False if not searchRes: return (headers , []) if service in ["mail", "samba"]: clVars, searchRes = searchRes if not searchRes: return (headers , []) # Добавляем директорию хранения писем для сервиса mail if service == "mail": for i in searchRes: i[0][1]['homeDirectory'] = [os.path.join(\ clVars.Get("sr_mail_path"),i[0][1]['uid'][0])] data.append((_("Home directory"),"homeDirectory")) # Добавляем директории пользователя для сервиса samba # а так же первичную и дополнительные группы if service == "samba": servObj = servSamba() for i in searchRes: primaryGroup = False # Ищем gidNumber пользователя Samба в Unix сервисе searchResUnix = servObj.servUnixObj.searchUnixUser(userName) if searchResUnix: #uidNumber = searchResUnix[0][0][1]['uidNumber'][0] #i[0][1]['uidNumber'] = [uidNumber] #data.insert(0,(_("ID"),"uidNumber")) gidNumber = searchResUnix[0][0][1]['gidNumber'][0] #sambaGroup = servObj.searchSambaGid(gidNumber) #if sambaGroup: i[0][1]['gidNumber'] = [gidNumber] data.append((_("Primary group"),"gidNumber")) homePath = os.path.join(\ clVars.Get("sr_samba_home_path"), i[0][1]['uid'][0]) if os.path.exists(homePath): i[0][1]['homePath'] = [homePath] data.append((_("Home directory"),"homePath")) sharePath = clVars.Get("sr_samba_share_path") if os.path.exists(sharePath): i[0][1]['sharePath'] = [sharePath] data.append((_("Share directory"),"sharePath")) linProfPath = os.path.join(\ clVars.Get("sr_samba_linprof_path"), i[0][1]['uid'][0]) if os.path.exists(linProfPath): i[0][1]['linProfPath'] = [linProfPath] data.append((_("Linux profile"),"linProfPath")) winProfPath = os.path.join(\ clVars.Get("sr_samba_winprof_path"), i[0][1]['uid'][0]) if os.path.exists(winProfPath): i[0][1]['winProfPath'] = [winProfPath] data.append((_("Windows profile"),"winProfPath")) winLogonPath = os.path.join(\ clVars.Get("sr_samba_winlogon_path"), i[0][1]['uid'][0]) if os.path.exists(winLogonPath): i[0][1]['winLogonPath'] = [winLogonPath] data.append((_("Windows logon"),"winLogonPath")) attributes = map(lambda x: x[0], data) retrAttrs = map(lambda x: x[1], data) data = [] lenRetrAttrs = len(retrAttrs) for info in searchRes: for i in range(lenRetrAttrs): attr = retrAttrs[i] attrName = attributes[i] if attr in info[0][1]: ldapValue = info[0][1][attr] # Изменяем значения аттрибутов для вывода на печать ldapValue[0] = self.modUserAttr(attr, ldapValue[0], service) flagFirst = False for value in ldapValue: if not flagFirst: data.append((attrName, value)) flagFirst = True else: data.append(("", value)) memberGroups = [] attrApp = "" if (service == "unix" and attr == "gidNumber") or\ (service == "samba" and attr == "gidNumber") or\ (service == "mail" and attr == "mailAlternateAddress")or\ (service == "proxy" and attr == "initials"): memberGroups = self._getUserMemberGroups(userName, service) attrApp = _("Supplementary groups") if service == "unix": if not value in memberGroups: memberGroups.insert(0,value) elif service == "samba": if value: if not value in memberGroups: memberGroups.insert(0,value) elif service == "mail": attrApp = _("Mail groups") elif service == "proxy": attrApp = _("Proxy groups") flagFirst = False for valueM in memberGroups: if not flagFirst: data.append((attrApp, valueM)) flagFirst = True else: data.append(("", valueM)) if not memberGroups: data.append((attrApp, _("No"))) else: data.append((attrName, _("No"))) dataClean = [] for name, value in data: if value: dataClean.append((name, value)) return (headers, dataClean) def getAllMachines(self, fields, service): """Выдает список компьютеров""" searchAttr = "uid" searchStr = "*" data, delData = self.genDataMachines(service, fields) if not data: self.printWARNING(_("Service %s has no machines")\ %self.printNameService(service)) return False if fields == "short": data = filter(lambda x: not x[0] in delData, data) headers = map(lambda x: x[0], data) retrAttrs = map(lambda x: x[1], data) machines = [] searchRes = self.getQueryLDAP(service, "computers", searchAttr, searchStr, retrAttrs) if searchRes == False: return False if not searchRes: return (headers , []) for info in searchRes: listAttr = [] for attr in retrAttrs: if attr in info[0][1]: ldapValue = info[0][1][attr] ldapValue[0] = self.modUserAttr(attr, ldapValue[0], service) # Если несколько значений то разделяем их запятыми value = reduce(lambda x,y: ",".join([x,y])[0] == "," and\ ",".join([x,y])[1:] or ",".join([x,y])[1:]\ and ",".join([x,y]) , ldapValue, "") listAttr.append(value) else: listAttr.append(_("No")) machines.append(listAttr) return (headers, machines) def getAllGroups(self, fields, service): """Выдает список всех групп и пользователей""" searchAttr = "cn" searchStr = "*" data, delData = self.genDataGroups(service, fields) if not data: self.printWARNING(_("Service %s has no groups")\ %self.printNameService(service)) return False if fields == "short": data = filter(lambda x: not x[0] in delData, data) headers = map(lambda x: x[0], data) retrAttrs = map(lambda x: x[1], data) groups = [] searchRes = self.getQueryLDAP(service, "groups", searchAttr, searchStr, retrAttrs) if searchRes == False: return False if not searchRes: return (headers , []) for info in searchRes: if service in ("proxy",): if info[0][1].has_key('member'): memberList = info[0][1]['member'] info[0][1]['member'] = map(lambda x: x.partition("=")[2],\ memberList) listAttr = [] # Добавляем первичные группы if service in ("unix", "samba"): memberUid = [] if info[0][1].has_key('memberUid'): memberUid = info[0][1]['memberUid'] groupId = info[0][1]['gidNumber'][0] primaryUids = self.getUnixUidPrimGroup(groupId) memberUid = primaryUids + memberUid uniqueUid = [] # Удаляем одинаковые элементы for uid in memberUid: if not uid in uniqueUid: uniqueUid.append(uid) if uniqueUid: info[0][1]['memberUid'] = uniqueUid for attr in retrAttrs: if attr in info[0][1]: ldapValue = info[0][1][attr] # Изменяем значения аттрибутов для вывода на печать ldapValue[0] = self.modGroupAttr(attr,ldapValue[0],service) #Если несколько значений то разделяем их запятыми value = reduce(lambda x,y: ",".join([x,y])[0] == "," and\ ",".join([x,y])[1:] or ",".join([x,y])[1:]\ and ",".join([x,y]) , ldapValue, "") listAttr.append(value) else: listAttr.append(_("No")) groups.append(listAttr) return (headers, groups) def genDataGroups(self, service, fields='full'): """Формирует поля нужные для вывода информации о группе""" data = [] delData = [] if service == "unix": data = [(_("Group"),"cn"), (_("Name"),"description"), ("GID","gidNumber"), (_("Member UID"),"memberUid")] if fields == "short": delData = [_("Member UID")] if service == "samba": data = [(_("Group"),"cn"), (_("Name"),"description"), ("GID","gidNumber"), (_("Group type"),"sambaGroupType"), (_("Member UID"),"memberUid")] if fields == "short": delData = [_("Name"), _("Member UID")] elif service == "mail": data = [(_("Group"),"cn"), (_("Name"),"description"), (_("Mail"),"mail"), (_("Alternate mail"),"mailAlternateAddress"), (_("Hide hosts"),"filtersender"), (_("Member UID"),"rfc822member")] if fields == "short": delData = [_("Mail"),_("Hide hosts"), _("Member UID")] elif service == "jabber": data = [(_("Group"),"cn"), (_("Comment"),"description")] if service == "proxy": data = [(_("Group"),"cn"), (_("Name"),"description"), (_("Range"),"o"), (_("Type"),"businessCategory"), (_("Member UID"),"member")] if fields == "short": delData = [_("Member UID")] return (data, delData) def genDataMachines(self, service, fields='full'): """Формирует поля нужные для вывода информации о компьютере""" data = [] delData = [] if service == "samba": data = [(_("ID"),"uidNumber"), (_("Login"),"uid"), (_("Name"),"cn"), (_("Primary group"),"gidNumber"), (_("Home directory"),"homeDirectory"), (_("Password"),"sambaNTPassword"), (_("Last change password"),"sambaPwdLastSet")] if fields == "short": delData = [_("Name"), _("Home directory"), _("Password"), _("Last change password")] return (data, delData) def genDataUsers(self, service, fields='full'): """Формирует поля нужные для вывода информации о пользователе""" data = [] delData = [] if service == "unix": data = [(_("ID"),"uidNumber"), (_("Login"),"uid"), (_("Name"),"cn"), (_("Lock"),"shadowExpire"), (_("Visible"),"shadowFlag"), (_("Primary group"),"gidNumber"), (_("Home directory"),"homeDirectory"), (_("Shell"),"loginShell"), (_("Password"),"userPassword"), (_("Last change password"),"shadowLastChange"), (_("Jabber ID"),"registeredAddress"), (_("Mail"),"mail")] if fields == "short": delData = [_("Lock"),_("Visible"),_("Shell"),_("Password"), _("Last change password"),_("Jabber ID"),_("Mail")] elif service == "samba": data = [(_("Login"),"uid"), (_("Name"),"displayName"), (_("Lock"),"sambaAcctFlags"), (_("Password"),"sambaNTPassword"), (_("Last change password"),"sambaPwdLastSet")] if fields == "short": delData = [_("Last change password")] elif service == "mail": data = [(_("Login"),"uid"), (_("Name"),"cn"), (_("Lock"),"accountStatus"), (_("Password"),"userPassword"), (_("Mail"),"mail"), (_("Alternate mail"),"mailAlternateAddress")] if fields == "short": delData = [_("Lock"), _("Password"), _("Mail")] elif service == "jabber": data = [(_("Login"),"uid"), (_("Name"),"sn"), (_("Group"),"departmentNumber"), (_("Jabber ID"),"mail"), (_("Lock"),"initials"), (_("Password"),"userPassword"), ] if fields == "short": delData = [_("Lock"), _("Group"), _("Password")] elif service == "ftp": data = [(_("ID"),"uidNumber"), (_("Login"),"uid"), (_("Name"),"cn"), (_("Primary group"),"gidNumber"), (_("Home directory"),"homeDirectory"), (_("Password"),"userPassword")] if fields == "short": delData = [_("ID"), _("Password"), _("Group")] elif service == "proxy": data = [(_("Login"),"uid"), (_("Name"),"sn"), (_("Lock"),"initials"), (_("Password"),"userPassword"), ] return (data, delData) def getAllUsers(self, fields, service): """Выдает список login-ов всех пользователей сервиса""" searchAttr = "uid" searchStr = "*" data, delData = self.genDataUsers(service, fields) if not data: self.printERROR(_("Incorrect service %s")\ %self.printNameService(service)) return False if fields == "short": data = filter(lambda x: not x[0] in delData, data) headers = map(lambda x: x[0], data) retrAttrs = map(lambda x: x[1], data) loginsUsers = [] retClVars=False if service == "mail": retClVars=True searchRes = self.getQueryLDAP(service, "users", searchAttr, searchStr, retrAttrs, retClVars) if searchRes == False: return False if not searchRes: return (headers , []) if service == "mail": clVars, searchRes = searchRes if not searchRes: return (headers , []) # Добавляем директорию хранения писем для сервиса mail for i in searchRes: i[0][1]['homeDirectory'] = [os.path.join(\ clVars.Get("sr_mail_path"),i[0][1]['uid'][0])] data.append((_("Home directory"),"homeDirectory")) delData.append(_("Home directory")) if fields == "short": data = filter(lambda x: not x[0] in delData, data) headers = map(lambda x: x[0], data) retrAttrs = map(lambda x: x[1], data) for info in searchRes: listAttr = [] for attr in retrAttrs: if attr in info[0][1]: ldapValue = info[0][1][attr] # Изменяем значения аттрибутов для вывода на печать ldapValue[0] = self.modUserAttr(attr, ldapValue[0], service) # Если несколько значений то разделяем их запятыми value = reduce(lambda x,y: ",".join([x,y])[0] == "," and\ ",".join([x,y])[1:] or ",".join([x,y])[1:]\ and ",".join([x,y]) , ldapValue, "") listAttr.append(value) else: listAttr.append(_("No")) loginsUsers.append(listAttr) return (headers, loginsUsers) def getUnixUidPrimGroup(self, groupId): """Находим пользователей с указанной первичной группой в сервисе Unix """ servObj = servUnix() searchUsers = servObj.searchUnixUserPrimGroup(groupId) users = [] if searchUsers: for dataUser in searchUsers: users.append(dataUser[0][1]['uid'][0]) return users def modGroupAttr(self, attr, value, service): """Модифицирует аттрибуты группы для вывода на печать""" retValue = value # Заменяем mail на имя пользователя if service == "mail" and attr == "rfc822member": servObj = servMail() searchUser = servObj.searchUserToMail(value) if searchUser: retValue = searchUser[0][0][1]['uid'][0] else: retValue = "Not found" # Заменяем тип группы названием типа if service == "samba" and attr == "sambaGroupType": if value == "2": retValue = _("domain group") if value == "4": retValue = _("local group") if value == "5": retValue = _("builtin group") return retValue def modUserAttr(self, attr, value, service): """Модифицирует аттрибуты пользователя для вывода на печать""" # Конвертируем время в текстовый формат retValue = value if attr == "shadowLastChange" or\ attr == "sambaPwdLastSet": retValue = self._convDatatoStr(value) # Находим имя группы elif attr == "gidNumber" and service in ("unix", "ftp"): retValue = self._getUserGroupName(value, "unix") elif attr == "gidNumber" and service in ("samba",): retValue = self._getUserGroupName(value, service) # Ставим Y в случае выставленного флага elif attr == "initials": if value == "No": retValue = _("Yes") else: retValue = _("No") elif attr == "accountStatus": if value == "passive": retValue = _("Yes") else: retValue = _("No") elif attr == "shadowExpire": if value == "1": retValue = _("Yes") else: retValue = _("No") elif attr == "sambaAcctFlags": if "D" in value: retValue = _("Yes") else: retValue = _("No") elif attr == "userPassword": if value == "crypt{xxx}": retValue = _("No") else: retValue = _("Yes") elif attr == "shadowFlag": if value == "1": retValue = _("Yes") else: retValue = _("No") elif attr == "sambaNTPassword": retValue = _("Yes") return retValue def _convDatatoStr(self, dataDays): """Конвертирует количество дней или секунд с 1970, в строку даты""" if dataDays: if len(str(dataDays)) <= 6: value = long(dataDays)*86400 elif len(str(dataDays)) > 6: value = long(dataDays) return reduce(lambda x,y: y+"."+x,map(lambda x: (len(str(x))==1 and\ "0"+str(x)) or str(x), time.localtime(value)[:3])) return "" def _getUserGroupName(self, userGid, service): """Находит имя группы по ее номеру""" try: exec ("servObj=serv%s()" %service.capitalize()) except: self.printERROR(\ _("ERROR: _getUserGroupName incorrect service=%s")%service) return False if service == "unix": retCondUnix, userGidNamesLdap, errMessUnix =\ servObj.searchGroupsUnix([userGid], False) userGidNamesLdap = userGidNamesLdap.keys() userGidNamesPasswd = servObj.searchGroupsGroups([userGid], False) if userGidNamesPasswd: #Имя группы пользователя groupName = userGidNamesPasswd[0] elif userGidNamesLdap: #Имя группы пользователя groupName = userGidNamesLdap[0] else: groupName = userGid return groupName if service == "samba": retCondSamba, userGidNamesLdap, errMessUnix =\ servObj.searchGroupsSamba([userGid], False) userGidNamesLdap = userGidNamesLdap.keys() if userGidNamesLdap: #Имя группы пользователя groupName = userGidNamesLdap[0] else: groupName = "" return groupName return userGid def _getUserMemberGroups(self, userName, service): """Находит имена групп в которые входит пользователь""" try: exec ("servObj=serv%s()" %service.capitalize()) except: self.printERROR(\ _("ERROR: _getUserGroupsNames incorrect service=%s")%service) return False memberGroups = [] if service == "unix": userInGroups = servObj.searchUnixMemberGid(userName) for group in userInGroups: memberGroups.append(group[0][1]['cn'][0]) if service == "samba": userInGroups = servObj.searchSambaMemberGid(userName) for group in userInGroups: memberGroups.append(group[0][1]['cn'][0]) if service == "proxy": userInGroups = servObj.searchMemberGroups(userName) for group in userInGroups: memberGroups.append(group[0][1]['cn'][0]) if service == "mail": resSearch = servObj.searchMailMember(userName) if not resSearch: return [] userMail, userInGroups = resSearch for group in userInGroups: mailGroup = group[0][1]['mail'] altMailGroup = group[0][1]['mailAlternateAddress'] listMail = mailGroup + altMailGroup for mail in listMail: if not mail in memberGroups: memberGroups.append(mail) return memberGroups class servProxy(shareLdap): """Методы сервиса Proxy""" relGrDN = 'ou=Groups' relUsDN = 'ou=Users' relServDN = 'ou=Proxy' ldifFileBase = "/usr/lib/calculate/calculate-server/ldif/proxy_base.ldif" ldifFileUser = "/usr/lib/calculate/calculate-server/ldif/proxy_user.ldif" ldifFileGroup = "/usr/lib/calculate/calculate-server/ldif/proxy_group.ldif" # Алгоритм шифрования пароля для Proxy пользователя userCrypt = "ssha" def __init__(self, unixObj=False): shareLdap.__init__(self) # DN сервиса self.relDN = self.addDN(self.relServDN,self.ServicesDN) # DN пользователей, относительно базового DN self.relUsersDN = self.addDN(self.relUsDN, self.relDN) # DN групп пользователей, относительно базового DN self.relGroupsDN = self.addDN(self.relGrDN, self.relDN) if unixObj: # получаем объект сервиса Unix self.servUnixObj = unixObj else: # создаем объект сервиса Unix self.servUnixObj = servUnix() def accessPort(self, userName, userPort, adminDn, adminPw, baseDN): """Доступ пользователя на основании порта""" try: numberUserPort = int(userPort) except: return False # Создаем объект переменных self.createClVars() # Записываем в переменную базовый DN self.clVars.Set("ld_base_dn", baseDN, True) # Если нужно подключаемся к LDAP if not self.ldapObj and not self.connectToLDAP(adminDn, adminPw): self.ldapObj = False return False # Ищем сервис Proxy в LDAP if not self.searchService() and not self.connectToLDAP(adminDn,adminPw): self.ldapObj = False return False resSearchGroups = self.searchMemberGroups(userName) flagAccess = False for group in resSearchGroups: ports = group[0][1]['o'][0] portsPar = ports.split(',') for port in portsPar: if "-" in port: portA,spl,portB = port.partition('-') try: rangePort = (int(portA),int(portB)) except: continue if numberUserPort<=max(rangePort) and\ numberUserPort>=min(rangePort): flagAccess = True break else: try: numberPort = int(port) except: continue if numberUserPort==numberPort: flagAccess = True break if flagAccess: return True return False def filterProxyServer(self, options): """Фильтр Proxy групп для доступа пользователя""" optPwd = ["p","P"] listOptPwd = filter(lambda x: x in optPwd, options.keys()) if len(listOptPwd) > 1: self.printERROR(_("Command line options '-p' and '-P' are \ incompatible, use one of the options")) return False if not (options.has_key("s") and options.has_key("b") and\ (options.has_key("p") or options.has_key("P"))): self.printERROR(_("Not found the options '-s' and '-b' and ('-p' \ or '-P')")) return False adminDn = options['s'] if options.has_key("p"): adminPw = options['p'] elif options.has_key("P"): pathPasswd = options['P'] if os.path.exists(pathPasswd): try: FD = open(pathPasswd, "r") adminPw = FD.read().strip() FD.close() except: self.printERROR(_("Can not read file %s") %pathPasswd) return False else: self.printERROR(_("Can not find file %s") %pathPasswd) return False if not adminPw: self.printERROR(_("Empty file %s") %pathPasswd) return False baseDN = options['b'] while True: try: strInput = sys.stdin.readline() strInput = strInput[:-1] params = map(lambda x: x, strInput.split(" ")) if params == ['']: sys.stdout.write("ERR\n") sys.stdout.flush() continue # Используем 2 параметра if len(params)>1: userName, userPort = params[:2] # Проверка доступа пользователя if self.accessPort(userName, userPort, adminDn, adminPw, baseDN): sys.stdout.write("OK\n") sys.stdout.flush() continue else: sys.stdout.write("ERR\n") sys.stdout.flush() except KeyboardInterrupt: break return True def searchGroupToName(self, groupName): """Находит группу сервиса Proxy по её имени""" resSearch = self.searchLdapDN(groupName, self.relGroupsDN, "cn") return resSearch def searchProxyGroups(self, groupNames): """Ищет группы. Находит все группы - True иначе - False""" notFindGroup=filter(lambda x: not self.searchGroupToName(x), groupNames) if notFindGroup: self.printERROR(_("Groups %s is not found in Proxy service")\ %", ".join(notFindGroup)) return False else: return True def searchUserToName(self, userName): """Находит пользователя сервиса Proxy""" resSearch = self.searchLdapDN(userName, self.relUsersDN, "uid") return resSearch @adminConnectLdap def addGroupProxyServer(self, groupName, options, checkSetup=True): """Добавляет группу пользователей Proxy""" # Проверим установлен ли сервис Proxy if checkSetup and not self.initialChecks("proxy"): return False # Если группа существует if self.searchGroupToName(groupName): self.printERROR(\ _("group name %s is found in Proxy service") %\ str(groupName)) return False self.clVars.Set("ur_group",groupName) # Комментарий к группе groupGecos = self.servUnixObj.groupGecos if options.has_key('c'): groupGecos = options['c'] self.clVars.Set("ur_group_comment",groupGecos) # Тип группы groupType = "port" accessPorts = "" if options.has_key('p'): accessPorts = options['p'] reFalseString = re.compile("[^\d,\-]|^,|^-|,-|-,|,$|-$") if reFalseString.search(accessPorts): self.printERROR(_("option '-p --port' %s (group port) \ is not valid ") %accessPorts) return False else: self.printERROR(_("Not found the option '-p --port'")) return False self.clVars.Set("ur_group_attr",accessPorts) self.clVars.Set("ur_group_type",groupType) ldifFile = self.ldifFileGroup groupLdif = self.createLdif(ldifFile) if not groupLdif: print self.getError() return False if not self.ldapObj.getError(): self.ldapObj.ldapAdd(groupLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False self.printSUCCESS(_("Added group '%s' in Proxy service")\ %groupName) return True def searchMemberGroups(self, userName): """Ищет группы сервиса Proxy в котрых есть данный пользователь""" resSearch = self.searchLdapDN("uid="+userName, self.relGroupsDN, "member") return resSearch def delUserInGroup(self, userName): """Удаление из групп в которые входит пользователь""" userInGroups = self.searchMemberGroups(userName) flagError = False for group in userInGroups: groupName = group[0][1]['cn'][0] lenMember = len(group[0][1]['member']) if lenMember == 1: modAttrs = [(ldap.MOD_REPLACE, 'member', "")] else: modAttrs = [(ldap.MOD_DELETE, 'member', "uid="+userName)] groupDN = self.addDN("cn=" + groupName, self.relGroupsDN) if not self.modAttrsDN(groupDN, modAttrs): flagError = True break if flagError: return False else: return True def delGroupProxyServer(self, groupName, options): """Удаляет группу пользователей Proxy""" # Проверим установлен ли сервис Proxy if not self.initialChecks("proxy"): return False res = self.searchGroupToName(groupName) if not res: self.printERROR(\ _("Group %s is not found in Proxy service")%groupName) return False delDN = self.addDN("cn="+groupName, self.relGroupsDN) res = self.delDN(delDN) if not res: self.printERROR(_("Can not delete Proxy group") +\ " " + groupName) return False else: self.printSUCCESS( _("Proxy group %s is deleted")%groupName) return True @adminConnectLdap def addUserProxyServer(self, userName, options): """Добавляет Proxy пользователя""" # Проверим установлен ли сервис Proxy if not self.initialChecks("proxy"): return False if self.searchUserToName(userName): self.printERROR(_("User %s exists in Proxy service") %userName) return False # Пароль пользователя Samba userPwd = self.getUserPassword(options, "p", "P") if userPwd == False: return False if not userPwd: userPwdHash = "crypt{xxx}" else: userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) self.clVars.Set("ur_hash", userPwdHash) self.clVars.Set("ur_name", userName) #Полное имя пользователя (комментарий) fullNameUser = self.servUnixObj.fullNameUser if options.has_key('c'): fullNameUser = options['c'] else: # Проверяем установку сервиса не печатая ошибку в случае # если сервис не установлен if self.isServiceSetup("unix",False): resUnix = self.servUnixObj.searchUnixUser(userName) # Берем комментарий для пользователя из Unix if resUnix and resUnix[0][0][1].has_key('cn'): fullNameUser = resUnix[0][0][1]['cn'][0] self.clVars.Set("ur_fio",fullNameUser) ldifFile = self.ldifFileUser userLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): #Добавляем пользователя в LDAP self.ldapObj.ldapAdd(userLdif) #ldapObj.ldapAdd(userLdif1) # не переделывать на else if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False self.printSUCCESS(_("Added user in Proxy service")) return True def addUsersGroupProxy(self, users, groupName): """Добавляет пользователей из списка в Proxy группу""" searchGroup = self.searchGroupToName(groupName) if not searchGroup: self.printERROR(_("Group name %s is not found in Proxy service")\ %str(groupName)) return False flagFalse = False for userName in users: if not self.searchUserToName(userName): self.printERROR(\ _("User %s is not found in Proxy service")%str(userName)) flagFalse = True break if flagFalse: return False modAttrs = [] # Группа не пуста flagEmptyGroup = False # Если есть пустой member аттрибут (пустая группа) if filter(lambda x: not x.strip(), searchGroup[0][0][1]['member']): flagEmptyGroup = True addUsers = users else: memberUsers = map(lambda x:x.rpartition("=")[2],\ searchGroup[0][0][1]["member"]) addUsers = filter(lambda x: not x in memberUsers, users) for userName in addUsers: if flagEmptyGroup: modAttrs.append((ldap.MOD_REPLACE, 'member', "uid="+userName)) flagEmptyGroup = False else: modAttrs.append((ldap.MOD_ADD, 'member', "uid="+userName)) if modAttrs: groupDN = self.addDN("cn="+groupName, self.relGroupsDN) return self.modAttrsDN(groupDN, modAttrs) return True def delUserProxyServer(self, userName, options): """Удаляем Proxy пользователя""" # Проверим установлен ли сервис proxy if not self.initialChecks("proxy"): return False # Ищем пользователя в Proxy resLdap = self.searchUserToName(userName) if not resLdap: self.printERROR (\ _("User %s is not found in Proxy service") % str(userName)) return False # Удаляем пользователя delDN = self.addDN("uid=" + userName, self.relUsersDN) if not self.delDN(delDN): return False # Удаляем пользователя из групп if not self.delUserInGroup(userName): return False self.printSUCCESS(_("User %s is deleted")%userName) return True def delUsersGroupProxy(self, users, groupName): """Удаление пользователей из списка из группы Proxy""" searchGroup = self.searchGroupToName(groupName) if not searchGroup: self.printERROR(_("Group name %s is not found in Proxy service")\ %str(groupName)) return False # Если группа пуста if filter(lambda x: not x.strip(), searchGroup[0][0][1]['member']): self.printERROR( _("Member list of group %s is empty")%str(groupName)) return False memberUsers = map(lambda x:x.rpartition("=")[2],\ searchGroup[0][0][1]["member"]) flagError = False for user in users: if not user in memberUsers: flagError = True break if flagError: self.printERROR( _("User %s is not found in group")%str(user)+" "+\ str(groupName)) return False modAttrs = [] lenMemberUsers = len(memberUsers) i = 0 for userName in users: i += 1 if i >= lenMemberUsers: modAttrs.append((ldap.MOD_REPLACE, 'member', "")) else: modAttrs.append((ldap.MOD_DELETE, 'member', "uid="+userName)) groupDN = self.addDN("cn="+groupName, self.relGroupsDN) return self.modAttrsDN(groupDN, modAttrs) def modUserProxyPasswd(self, userName, options): """Устанавливает пароль LDAP пользователя и меняет его опции""" # Проверим установлен ли сервис Proxy if not self.initialChecks("proxy"): return False res = self.searchUserToName(userName) if not res: self.printERROR( _("User %s is not found in Proxy service")%str(userName)) return False # Изменяемые аттрибуты пользователя modAttrs = [] # Включаем пользователя if options.has_key('u'): modAttrs += [(ldap.MOD_REPLACE, 'initials', "Yes")] # Выключаем пользователя elif options.has_key('l'): modAttrs += [(ldap.MOD_REPLACE, 'initials', "No")] if not options: optPasswd = {"p":""} userPwd = self.getUserPassword(optPasswd, "p", False) if userPwd == False: return False userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) if not userPwdHash: return False if res[0][0][1].has_key('userPassword'): modAttrs.append((ldap.MOD_REPLACE, 'userPassword', userPwdHash)) else: modAttrs.append((ldap.MOD_ADD, 'userPassword', userPwdHash)) if modAttrs: DN = self.addDN("uid="+userName, self.relUsersDN) if not self.modAttrsDN(DN, modAttrs): return False if options.has_key('l'): self.printSUCCESS(_("Locked user") + " " + str(userName) +\ " " +_("of Proxy service")) if options.has_key('u'): self.printSUCCESS(_("Unlocked user") + " " + str(userName) +\ " " +_("of Proxy service")) if not options: self.printSUCCESS(_("User password of Proxy service changed")) return True return False def modUserProxyServer(self, userName, options): """Модифицирует настройки пользователя Proxy""" # Проверим установлен ли сервис Proxy if not self.initialChecks("proxy"): return False res = self.searchUserToName(userName) if not res: self.printERROR( _("User %s is not found in Proxy service")%str(userName)) return False # Новые группы в которые входит пользователь if options.has_key('G'): userGroups = options['G'].split(',') if not self.searchProxyGroups(userGroups): return False # Удаляем Proxy пользователя из групп в которые он входит if not self.delUserInGroup(userName): return False flagError = False for group in userGroups: if not self.addUsersGroupProxy([userName], group): flagError = True break if flagError: return False self.printSUCCESS(_("Replaced list of supplementary group")) # Добавляем группы в которые входит пользователь elif options.has_key('a'): userGroups = options['a'].split(',') if not self.searchProxyGroups(userGroups): return False flagError = False for group in userGroups: if not self.addUsersGroupProxy([userName], group): flagError = True break if flagError: return False self.printSUCCESS(_("Appended the user to the supplemental groups")) # Изменяемые аттрибуты пользователя modAttrs = [] # Включаем пользователя if options.has_key('U'): modAttrs += [(ldap.MOD_REPLACE, 'initials', "Yes")] # Выключаем пользователя elif options.has_key('L'): modAttrs += [(ldap.MOD_REPLACE, 'initials', "No")] # Изменяем комментарий к пользователю if options.has_key('c'): comment = options['c'] modAttrs += [(ldap.MOD_REPLACE, 'sn', comment), (ldap.MOD_REPLACE, 'cn', comment)] # Изменяем пароль пользователя userPwd = self.getUserPassword(options, "p", "P") if userPwd == False: return False if userPwd: userPwdHash = self.getHashPasswd(userPwd, self.userCrypt) if not userPwdHash: return False if res[0][0][1].has_key('userPassword'): modAttrs.append((ldap.MOD_REPLACE, 'userPassword', userPwdHash)) else: modAttrs.append((ldap.MOD_ADD, 'userPassword', userPwdHash)) if modAttrs: DN = self.addDN("uid="+userName, self.relUsersDN) if not self.modAttrsDN(DN, modAttrs): return False if options.has_key('P') or options.has_key('p'): self.printSUCCESS(_("Modified user password")) if options.has_key('c'): self.printSUCCESS(_("Modified comment")) if options.has_key('U'): self.printSUCCESS(_("Unlocked user %s")% str(userName)) if options.has_key('L'): self.printSUCCESS(_("Locked user %s")% str(userName)) return True def modGroupProxyServer(self, groupName, options): """Модифицирует настройки группы пользователей Proxy""" # Проверим установлен ли сервис proxy if not self.initialChecks("proxy"): return False searchGroup = self.searchGroupToName(groupName) if not searchGroup: self.printERROR(_("Group name %s is not found in Proxy service")\ %str(groupName)) return False # Добавляем список пользователей в группу if options.has_key('a'): # добавляемые пользователи в группу users = options['a'].split(',') res = self.addUsersGroupProxy(users, groupName) if res: self.printSUCCESS(_("Appended list users to group") + " " +\ str(groupName)) else: self.printERROR(_("Can not append list users to group") +\ " " + str(groupName)) return False # Удаляем список пользователей из группы if options.has_key('d'): # удаляемые пользователи из группы users = options['d'].split(',') res = self.delUsersGroupProxy(users, groupName) if res: self.printSUCCESS(_("Deleted list users from group") + " " +\ str(groupName)) else: self.printERROR(_("Can not delete list users from group") +\ " " + str(groupName)) return False # Изменяем комментарий к группе if options.has_key('c'): gecos = options['c'] modAttrs = [(ldap.MOD_REPLACE, 'description', gecos)] groupDN = self.addDN("cn="+groupName, self.relGroupsDN) if self.modAttrsDN(groupDN, modAttrs): self.printSUCCESS(_("Modified group comment")) else: self.printERROR(_("Can not modify comment group") +\ " " + str(groupName)) return False # Изменяем имя группы if options.has_key('n'): newGroupName = options['n'] newFirstDn = "cn=" + newGroupName oldDN = self.addDN("cn=" + groupName, self.relGroupsDN) res = self.modifyElemDN(oldDN, newFirstDn) if res: self.printSUCCESS(_("Group renamed to %s")\ %newGroupName) else: self.printERROR(_("Can not rename group") +\ " " + str(groupName)) return False return True def getAllowNet(self): """Получаем от пользователя доверительные сети и устанавливаем переменную профилей sr_proxy_net_allow self.clVars должен быть определен """ print _("Enter the allowed ip addresses and network for %s service")\ %"Proxy" + " (" + _("comma or space delimited") + ")" strPrompt = _("allow networks: ") netAllow = self.clVars.Get("sr_proxy_net_allow") strNetAllow = "" if netAllow: strNetAllow = netAllow.replace(","," ") allowNet = self.getUserAllowNetwork(strPrompt, strNetAllow) if not allowNet: return False # Установка переменной доступные сети allowNet = ",".join(allowNet) self.clVars.Set("sr_proxy_net_allow", allowNet ,True) return allowNet def setupProxyServer(self, options): """Начальная настройка Proxy сервиса""" # Принудительная установка forceOptions = False if options.has_key("f"): forceOptions = True # Создаем объект переменных и начальная проверка if not self.initialChecksSetup(): return False if self.clVars.Get("sr_ldap_set") != "on": self.printERROR(_("LDAP service is not setuped")) self.printWARNING(_("Setup LDAP service")) self.printWARNING(" cl-setup ldap") return False # В случае если сервер установлен if self.clVars.Get("sr_proxy_set") == "on" and\ not forceOptions: self.printWARNING (_("WARNING") + ": " +\ _("Proxy server is configured")+ ".") return True # Порт для прокси сервера if options.has_key("p"): proxyPort = options['p'] try: numberProxyPort = int(proxyPort) except: self.printERROR(_("Option '-p' is not number")) return False proxyPort = str(numberProxyPort) # Доверительные сети по умолчанию allowNet = self.clVars.Get("os_net_allow") if not forceOptions: # предупреждение при выполнении этой программы будут изменены # конфигурационные файлы сервиса Proxy (программa squid) self.printWARNING (_("WARNING") + ": " + _("Executing of the program will change") + " " + _("the configuration files of Proxy service") +" ("+ _("program squid") + ")." ) # если вы готовы продолжить работу программы нажмите Y если нет n messDialog = \ _("If you are ready to continue executing the program") + ", "+\ _("input 'yes'") +", "+ _("if not 'no'") if not self.dialogYesNo(messDialog): return True if options.has_key("a"): # Получаем от пользователя доверительные сети allowNet = self.getAllowNet() if not allowNet: return False else: if options.has_key("a"): # Получаем от пользователя доверительные сети allowNet = self.getAllowNet() if not allowNet: return False # делаем backup # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False bakupObj = servLdap() if not bakupObj.backupServer(): return False # Удаляем переменные сервиса в ini файлах self.deleteServiceVarsInFile("proxy") # Cоздаем объект переменные self.createClVars() # Устанавливаем доступные сети self.clVars.Set("sr_proxy_net_allow", allowNet, True) if options.has_key("p"): self.clVars.Set("sr_proxy_port",proxyPort, True) # Удаляем из автозапуска демона if not self.delDaemonAutostart("squid"): return False # останавливаем сервис Proxy if not self.stopServices(["proxy"]): return False # Имя устанавливаемого сервиса self.clVars.Set("cl_pass_service","proxy") self.clVars.Write("sr_proxy_set","off") # Proxy host fullHostName = "%s.%s"%(self.clVars.Get('os_net_hostname'), self.clVars.Get('os_net_domain')) jabberHosts = fullHostName if options.has_key("host"): fullHostName = options['host'] if not "." in fullHostName: fullHostName = "%s.%s" %(fullHostName, self.clVars.Get('os_net_domain')) self.clVars.Set("sr_proxy_host",fullHostName,True) # Cоздаем объект профиль устанавливая директорию proxy для # файлов профилей if not self.applyProfilesFromService('proxy'): return False # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False else: if not self.restartLdapServer(): return False # Подключаемся к LDAP cерверу if not shareLdap.getLdapObjInFile(self): return False # Находим в LDAP Proxy сервис resSearch = self.searchService() ret = True if resSearch: delDN = self.relDN ret = self.deleteDN(delDN) if ret: self.printOK(_("Remove Proxy DN from LDAP Database") + " ...") else: self.printERROR(\ _("Can not remove Proxy DN from LDAP Database")) if not ret: return False ldifFile = self.ldifFileBase baseLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): self.ldapObj.ldapAdd(baseLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False # Записываем данные администратора сервиса Proxy ldapParser = iniLdapParser() ldapParser.setVar("proxy", {"DN":self.clVars.Get("ld_proxy_dn"), "PASS":self.clVars.Get("ld_proxy_pw")}) self.printOK(_("Added ldif file") + " ...") textLines = self.execProg("/etc/init.d/squid start") if textLines == False: self.printNotOK(_("Starting") + " " + "Squid" + " ...") return False else: self.printOK(_("Starting") + " " + "Squid" + " ...") # Устанавливаем автозапуск демона if not self.setDaemonAutostart("squid"): return False # добавим группы доступа http и ftp flagError = False groupInfo = (('http','80','http access group'), ('ftp','21','ftp access group'), ('https','443','https access group'), ('gopher','70','gopher access group'), ('wais','210','wais access group'), ('unregistered','1025-65535','unregistered ports access \ group'), ('http-mgmt','280','http-mgmt access group'), ('gss-http','488','gss-http access group'), ('filemaker','591','filemaker access group'), ('multiling','777','multiling http access group'), ('swat','901','SWAT access group')) for groupName, groupPort, groupDesc in groupInfo: if not self.addGroupProxyServer(groupName, {'p':groupPort, 'c':groupDesc}, False): flagError = True break if flagError: return False # запишем переменные для сервера proxyHost = self.clVars.Get("sr_proxy_host") self.clVars.Write("sr_proxy_host",proxyHost,True,"local") proxyPort = self.clVars.Get("sr_proxy_port") self.clVars.Write("sr_proxy_port",proxyPort,True,"local") allow = self.clVars.Get("sr_proxy_net_allow") self.clVars.Write("sr_proxy_net_allow",allow,True,"local") # запишем переменные для клиента clientVars = ["sr_proxy_host","sr_proxy_port"] if not self.saveVarsClient(clientVars): return False self.clVars.Write("sr_proxy_set","on") self.printOK(_("Proxy service configured") + " ...") return True class shareTxt(cl_profile._error, cl_utils2.cl_smartcon): """Общий класс наследования для классов работающих с текстом""" def _printTxtERROR(self): """Печать ошибок из объекта обработки текста""" error = self.getError() if not error: return False errorMessagesList = error.split("\n") if not errorMessagesList: return False for error in errorMessagesList: if error.strip(): self.printERROR(error) return True def setError(self, text): ret = cl_profile._error.setError(self, text) self._printTxtERROR() return ret def writeInConfig(self, text): """Запись текста в конфигурационный файл""" try: FD = open(self.nameConfigFile,"r+") FD.truncate(0) FD.seek(0) FD.write(text) FD.close() except: errMessage = _("Can not write in file %s") %self.nameConfigFile self.printERROR(errMessage) self.setError(errMessage) return False return True class dncpTxt(cl_profile.dhcp, shareTxt, shareIP): """Класс для работы с текстом конфиг. файла dhcp""" # Имя конфигурационного файла nameConfigFile = "/etc/dhcp/dhcpd.conf" # Параметры сети dataParsNet = {"net":[], "mask":[], "range":[], "optionbroadcast-address":[], "optionsubnet-mask":[], "optionrouters":[], "optiondomain-name":[], "optiondomain-name-servers":[]} # Параметры статического хоста dataParsHost = {"host":[], "fixed-address":[], "hardwareethernet":[]} def __init__(self): try: FD = open(self.nameConfigFile) text = FD.read() FD.close() except: errMessage = _("Can not open %s") %self.nameConfigFile self.setError(errMessage) if not self.getError(): cl_profile.dhcp.__init__(self, text) def getTextStaticIP(self, hostname, ip, mac): """Создание текста для добавления статического адреса""" templateList = [(hostname, 'host %s {'%hostname), (ip, '\tfixed-address %s;'%ip), (mac,'\thardware ethernet %s;'%mac), (True, '}')] templateList = map(lambda x: x[1], filter(lambda x: x[0], templateList)) template = "".join(templateList) return template def getTextSubnet(self, net, broadcastAddress, routers, domainName, domainNameServers, iprange, subnetMask="255.255.255.0", netmask="255.255.255.0", deleteOpt=False): """Создание текста для добавления подсети""" delChar = "" if deleteOpt: delChar = "!" templateList = [(net, 'subnet %s '%net), (netmask, 'netmask %s {'%netmask), (broadcastAddress, '\t%soption broadcast-address %s;'\ %(delChar, broadcastAddress)), (subnetMask, '\t%soption subnet-mask %s;'\ %(delChar, subnetMask)), (routers, '\t%soption routers %s;'%(delChar, routers)), (domainName, '\t%soption domain-name "%s";'\ %(delChar, domainName)), (domainNameServers,'\t%soption domain-name-servers %s;'\ %(delChar,domainNameServers)), (iprange, '\t%srange %s;'%(delChar, iprange)), (True, '}')] templateList = map(lambda x: x[1], filter(lambda x: x[0], templateList)) template = "".join(templateList) return template def _getAllXMLStaticHosts(self): """Получаем все XML ноды статических хостов""" if self.getError(): return False xmlNodeBody = self.docObj.getNodeBody() namesArea = xpath.Evaluate(\ "child::area/child::caption/child::name", xmlNodeBody) if not namesArea: return [] return filter(lambda x: x.firstChild and x.firstChild.nodeValue and\ len(x.firstChild.nodeValue) > 4 and\ 'host' in x.firstChild.nodeValue[:4], namesArea) def getAllXMLSubnet(self): """Получаем все XML ноды подсетей""" if self.getError(): return False xmlNodeBody = self.docObj.getNodeBody() namesArea = xpath.Evaluate(\ "child::area/child::caption/child::name", xmlNodeBody) if not namesArea: return [] return filter(lambda x: x.firstChild and x.firstChild.nodeValue and\ len(x.firstChild.nodeValue) > 6 and\ 'subnet' in x.firstChild.nodeValue[:6], namesArea) def getDataInAllHost(self): """Получить информацию о статических хостах""" if self.getError(): return False allXmlNames = self._getAllXMLStaticHosts() allXmlAreas = map(lambda x: x.parentNode.parentNode, allXmlNames) # Информация dataHost = [] iterXmlNames = iter(allXmlNames) for xmlArea in allXmlAreas: #print xmlArea.toprettyxml() # Ност xmlNodeName = iterXmlNames.next() strNameNode = xmlNodeName.firstChild.nodeValue # название хоста hostname = strNameNode.partition("host")[2].strip().encode("UTF-8") # Параметры статического хоста dataPars = self.dataParsHost.copy() # Заполняем словарь dataPars реальными параметрами dataPars = self.getDataInNode(xmlArea, dataPars) dataPars["host"] = [hostname] dataHost.append([hostname, dataPars]) return dataHost def getDataInAllSubnet(self): """Получить информацию о сетях""" if self.getError(): return False allXmlNames = self.getAllXMLSubnet() allXmlAreas = map(lambda x: x.parentNode.parentNode, allXmlNames) # Информация dataNet = [] iterXmlNames = iter(allXmlNames) for xmlArea in allXmlAreas: # Сеть xmlNodeName = iterXmlNames.next() # Название области strNameNode = xmlNodeName.firstChild.nodeValue # ip сети netIP = strNameNode.partition("subnet")[2].partition("netmask")[0] netIP = netIP.encode("UTF-8") # Маска сети netMask = strNameNode.partition("subnet")[2].partition("netmask")[2] netMask = netMask.encode("UTF-8") # Параметры сети dataPars = self.dataParsNet.copy() # Заполняем словарь dataPars реальными параметрами dataPars = self.getDataInNode(xmlArea, dataPars) dataPars["net"] = [netIP] dataPars["mask"] = [netMask] dataNet.append([netIP, dataPars]) return dataNet def convertNetMask(self, ipNetMask): """Преобразует ip маску сети в число""" def isNumber(string): """Проверка на число""" try: int(string) except: return False return True def strToBinList(string): """Преобразует число в двоичный код список""" binList = [] numb = int(string) while numb: binList.append(numb%2) numb = numb/2 return binList[::-1] listOctMask = ipNetMask.split('.') if filter(lambda x: not isNumber(x), listOctMask): return "" countOne = lambda z: filter(lambda x:x==1, strToBinList(z)) numberMask = sum(map(lambda x: sum(countOne(x)), listOctMask)) return str(numberMask) def getDataInNode(self, xmlArea, dataPars): """Информация о сети по ее XML ноде Информация dataPars """ for opt in dataPars.keys(): nodesFind = xpath.Evaluate("child::field[child::name='%s']"%opt,\ xmlArea) for node in nodesFind: nodesXml = xpath.Evaluate("child::value", node) for nodeFind in nodesXml: if nodeFind.firstChild: listOpt = map(lambda x: x.encode("UTF-8"),\ filter(lambda x: x,\ nodeFind.firstChild.nodeValue.replace("\t",\ " ").split(" "))) dataPars[opt] = listOpt return dataPars def getXMLStaticHost(self, hostName): """Получить XML ноду cтатического хоста по его имени""" if self.getError(): return False # Получаем ноды всех статических хостов xmlStaticHosts = self._getAllXMLStaticHosts() if not xmlStaticHosts: return [] slpHostName = 'host%s' %hostName.lower() return map(lambda x: x.parentNode.parentNode, filter(lambda x:\ slpHostName == x.firstChild.nodeValue.lower(), xmlStaticHosts)) def getXMLNet(self, net): """Получить XML ноду подсети по ip""" if self.getError(): return False # Получаем ноды всех подсетей xmlSubnets = self.getAllXMLSubnet() if not xmlSubnets: return [] slpNetName = 'subnet%s' %net.lower() lenSlpNetName = len(slpNetName) return map(lambda x: x.parentNode.parentNode, filter(lambda x:\ len(x.firstChild.nodeValue)>lenSlpNetName and\ slpNetName==x.firstChild.nodeValue[:lenSlpNetName].lower(),\ xmlSubnets)) def createStaticHost(self, hostname, ip, mac): """Создает статический хост в файле конфигурации dhcp""" if self.getError(): return False textHost = self.getTextStaticIP(hostname, ip, mac) dhcpObj = cl_profile.dhcp(textHost) xmlNodeBodyNewNet = dhcpObj.docObj.getNodeBody() namesAreaNew = xpath.Evaluate("child::area/child::caption/child::name", xmlNodeBodyNewNet) splNameNewNode = namesAreaNew[0].firstChild.nodeValue hostnameNode = splNameNewNode.partition("host")[2].strip() if self.getXMLStaticHost(hostnameNode): self.setError(_('DHCP static host "%s" exists')%hostnameNode) return False # Объединение конфигураций self.join(dhcpObj) # Запись файла text = self.getConfig().encode("UTF-8") return self.writeInConfig(text) def modNetOpts(self,xmlNode,routers="",domainName="",dnsIPs="",iprange=""): """Модифицирует опции сети: routers, domainName, iprange""" if self.getError(): return False namesArea = xpath.Evaluate("child::caption/child::name", xmlNode) splNameNewNode = namesArea[0].firstChild.nodeValue netIPList = splNameNewNode.partition("subnet")[2].partition("netmask") netIP = netIPList[0].strip().encode("UTF-8") netMask = netIPList[2].partition("{")[0].strip().encode("UTF-8") if not filter(lambda x: x, (routers, domainName, dnsIPs, iprange)): self.setError(_("empty modify options")) return False textNet = self.getTextSubnet(netIP, "", routers, domainName, dnsIPs, iprange, subnetMask="", netmask=netMask) dhcpObj = cl_profile.dhcp(textNet) # Объединение конфигураций self.join(dhcpObj) # Запись файла text = self.getConfig().encode("UTF-8") return self.writeInConfig(text) def modHostOpts(self, xmlNode, ip, mac): """Модифицирует опции хоста: ip, mac""" if self.getError(): return False namesArea = xpath.Evaluate("child::caption/child::name", xmlNode) splNameNewNode = namesArea[0].firstChild.nodeValue hostname = splNameNewNode.partition("host")[2].strip().encode("UTF-8") if not filter(lambda x: x, (ip, mac)): self.setError(_("empty modify options")) return False textHost = self.getTextStaticIP(hostname, ip, mac) dhcpObj = cl_profile.dhcp(textHost) # Объединение конфигураций self.join(dhcpObj) # Запись файла text = self.getConfig().encode("UTF-8") return self.writeInConfig(text) def createNet(self, net, routers, domainNames, dnsIPs, ipranges): """Создает cеть в файле конфигурации dhcp""" if self.getError(): return False network, spl, netmask = net.rpartition("/") minNumber, maxNumber = self.getMinAndMaxIpNumb(net) broadcastAddress = self.getIPinNumber(maxNumber) numbNetmask = self.getNumberNetmask(netmask) subnetMask = self.getIPinNumber(numbNetmask) netmask = subnetMask domainName = reduce(lambda x,y: "%s %s"%(x,y) , domainNames, "").strip() iprange = "%s %s"%(ipranges[0],ipranges[1]) textNet = self.getTextSubnet(network, broadcastAddress, routers, domainName,dnsIPs, iprange, subnetMask=subnetMask, netmask=netmask) dhcpObj = cl_profile.dhcp(textNet) xmlNodeBodyNewNet = dhcpObj.docObj.getNodeBody() namesAreaNew = xpath.Evaluate("child::area/child::caption/child::name", xmlNodeBodyNewNet) splNameNewNode = namesAreaNew[0].firstChild.nodeValue netIP = splNameNewNode.partition("subnet")[2].partition("netmask")[0] netIP = netIP.encode("UTF-8") if self.getXMLNet(netIP): self.setError(_('DHCP subnet "%s" exists')%netIP) return False # Объединение конфигураций self.join(dhcpObj) # Запись файла text = self.getConfig().encode("UTF-8") return self.writeInConfig(text) def deleteAllNetAndHosts(self): """Удаляет все сети и статические хосты из конфигурационного файла""" # IP всех сетей delNamesNets = map(lambda x:\ x.firstChild.nodeValue.partition("subnet")[2].partition("netmask")[0].\ encode("UTF-8"), filter(lambda x: x.firstChild, self.getAllXMLSubnet())) # Имена всех статических хостов delNamesHosts = map(lambda x:\ x.firstChild.nodeValue.partition("host")[2].strip().encode("UTF-8"),\ filter(lambda x: x.firstChild, self._getAllXMLStaticHosts())) # Удаление for term in map(lambda x: self.deleteNet(x), delNamesNets): if not term: return False for term in map(lambda x: self.deleteStaticHost(x), delNamesHosts): if not term: return False return True def deleteStaticHost(self, hostname): """Удаляет статических хост из конфигурационного файла""" if self.getError(): return False deletesNodes = self.getXMLStaticHost(hostname) if not deletesNodes: self.setError(\ _('Can not found static host "%s" in /etc/dhcp/dhcpd.conf')\ %hostname) return False # Удаление областей xmlNodeBody = self.docObj.getNodeBody() nextNode = lambda x: x.nextSibling prevNode = lambda x: x.previousSibling delNodesNext = [] delNodesPrev = [] for node in deletesNodes: nNode = node nNode = nextNode(nNode) while nNode and self.docObj.getTypeField(nNode)=="br": delNodesNext.append(nNode) nNode = nextNode(nNode) pNode = node pNode = prevNode(pNode) while pNode and self.docObj.getTypeField(pNode)=="br": delNodesPrev.append(pNode) pNode = prevNode(pNode) # Оставляем два перевода строки сверху if delNodesPrev and len(delNodesPrev)>=2: delNodesPrev.pop() delNodesPrev.pop() elif delNodesNext and len(delNodesNext)>=2: delNodesNext.pop() delNodesNext.pop() elif delNodesPrev and len(delNodesPrev)==1: delNodesPrev.pop() if delNodesNext and len(delNodesNext)==1: delNodesNext.pop() elif delNodesNext and len(delNodesNext)==1: delNodesNext.pop() delNodes = delNodesPrev + delNodesNext # Удаляем переводы строк map(lambda x: xmlNodeBody.removeChild(x), delNodes) #print xmlNodeBody.toprettyxml().encode("UTF-8") # Удаляем области for term in map(lambda x: xmlNodeBody.removeChild(x), deletesNodes): if not term: self.setError(_('Can not remove static host "%s"')%hostname+\ " " + _("in config file %s")%self.nameConfigFile) return False # Запись файла text = self.getConfig().encode("UTF-8") return self.writeInConfig(text) def deleteNet(self, net): """Удаляет подсеть из конфигурационного файла""" if self.getError(): return False deletesNodes = self.getXMLNet(net) if not deletesNodes: self.setError(\ _('Can not found subnet "%s" in /etc/dhcp/dhcpd.conf')\ %net) return False # Удаление областей xmlNodeBody = self.docObj.getNodeBody() nextNode = lambda x: x.nextSibling prevNode = lambda x: x.previousSibling delNodesNext = [] delNodesPrev = [] for node in deletesNodes: nNode = node nNode = nextNode(nNode) while nNode and self.docObj.getTypeField(nNode)=="br": delNodesNext.append(nNode) nNode = nextNode(nNode) pNode = node pNode = prevNode(pNode) while pNode and self.docObj.getTypeField(pNode)=="br": delNodesPrev.append(pNode) pNode = prevNode(pNode) # Оставляем два перевода строки сверху if delNodesPrev and len(delNodesPrev)>=2: delNodesPrev.pop() delNodesPrev.pop() elif delNodesNext and len(delNodesNext)>=2: delNodesNext.pop() delNodesNext.pop() elif delNodesPrev and len(delNodesPrev)==1: delNodesPrev.pop() if delNodesNext and len(delNodesNext)==1: delNodesNext.pop() elif delNodesNext and len(delNodesNext)==1: delNodesNext.pop() delNodes = delNodesPrev + delNodesNext # Удаляем переводы строк map(lambda x: xmlNodeBody.removeChild(x), delNodes) #print xmlNodeBody.toprettyxml().encode("UTF-8") # Удаляем области for term in map(lambda x: xmlNodeBody.removeChild(x), deletesNodes): if not term: self.setError(_('Can not remove subnet "%s"')%net+\ " " + _("in config file %s")%self.nameConfigFile) return False # Запись файла text = self.getConfig().encode("UTF-8") return self.writeInConfig(text) class dnsTxt(cl_profile.bind,shareTxt): """Класс для работы с DNS зонами в тексте конфиг. файла named.conf""" # Имя конфигурационного файла nameConfigFile = "/etc/bind/named.conf" def __init__(self): try: FD = open(self.nameConfigFile) text = FD.read() FD.close() except: errMessage = _("Can not open %s") %self.nameConfigFile self.setError(errMessage) if not self.getError(): cl_profile.bind.__init__(self, text) def getTextZone(self, clVars, zoneName, zoneType, zoneMasters=[]): """Создание текста DNS зоны""" if zoneType == "master": dnsBaseDN = clVars.Get("ld_dns_dn") dnsCommaSplDN = dnsBaseDN.replace(",","%2c") dnsBasePw = clVars.Get("ld_dns_pw") if ".in-addr.arpa" in zoneName: dnsDN = "ou=Reverse,%s"%dnsBaseDN # реверсивная зона else: # прямая зона dnsDN = "ou=Forward,%s"%dnsBaseDN template = 'zone "%s" in {\n\ \ttype %s;\n\ \tdatabase "ldap ldap://127.0.0.1/zoneName=%s,%s????\ !bindname=%s,!x-bindpw=%s 178600";\n\ };' %(zoneName,zoneType,zoneName,dnsDN,dnsCommaSplDN,dnsBasePw) return template elif zoneType == "slave": if not zoneMasters: self.setError(\ _('Can not found master DNS server in the DNS zone "%s"')%zoneName) return False zoneFile = "%s.zone" %zoneName.split(".in-addr.arpa")[0] template = 'zone "%s" {\n\ \ttype %s;\n\ \tfile "sec/%s";\n\ \tmasters { %s; };\n\ };' %(zoneName,zoneType,zoneFile, "; ".join(zoneMasters)) return template else: self.setError(_('DNS zone type %s unsupported')%zoneType) return False def _getAllXMLZonesNames(self): """Получаем все XML ноды названий DNS зон""" if self.getError(): return False xmlNodeBody = self.docObj.getNodeBody() namesArea = xpath.Evaluate(\ "child::area/child::caption/child::name", xmlNodeBody) if not namesArea: return [] return filter(lambda x: x.firstChild and x.firstChild.nodeValue and\ 'zone"' in x.firstChild.nodeValue, namesArea) def getXMLZoneToName(self, nameZone): """Получить XML ноду DNS зоны по ее имени""" if self.getError(): return False if nameZone in [".", "localhost", "127.in-addr.arpa"]: return [] # Получаем ноды зон xmlZonesNames = self._getAllXMLZonesNames() if not xmlZonesNames: return [] nameZoneL = nameZone.lower() return map(lambda x: x.parentNode.parentNode, filter(lambda x:\ nameZoneL == \ x.firstChild.nodeValue.lower().partition('"')[2].partition('"')[0],\ xmlZonesNames)) def getAllNamesZones(self): """Получить все имена нод областей (кроме служебных)""" if self.getError(): return False retNodesNames = [] # Получаем ноды зон xmlZonesNames = self._getAllXMLZonesNames() if not xmlZonesNames: return retNodesNames for nodeZone in xmlZonesNames: if '"."' in nodeZone.firstChild.nodeValue.lower(): continue elif '"localhost"' in nodeZone.firstChild.nodeValue.lower(): continue elif '"127.in-addr.arpa"' in nodeZone.firstChild.nodeValue.lower(): continue retNodesNames.append(\ nodeZone.firstChild.nodeValue.rpartition('"')[0].partition('"')[2]) retNodesNames = filter(lambda x: x, retNodesNames) return map(lambda x: x.encode("UTF-8"), retNodesNames) def deleteZone(self, zoneName): """Удаляет зону из конфигурационного файла bind""" if self.getError(): return False deletesNodes = self.getXMLZoneToName(zoneName) if not deletesNodes: self.setError(\ _('Can not found DNS zone "%s" in /etc/bind/named.conf')\ %zoneName) return False # Удаление областей xmlNodeBody = self.docObj.getNodeBody() nextNode = lambda x: x.nextSibling prevNode = lambda x: x.previousSibling delNodesNext = [] delNodesPrev = [] for node in deletesNodes: nNode = node nNode = nextNode(nNode) while nNode and self.docObj.getTypeField(nNode)=="br": delNodesNext.append(nNode) nNode = nextNode(nNode) pNode = node pNode = prevNode(pNode) while pNode and self.docObj.getTypeField(pNode)=="br": delNodesPrev.append(pNode) pNode = prevNode(pNode) # Оставляем два перевода строки сверху if delNodesPrev and len(delNodesPrev)>=2: delNodesPrev.pop() delNodesPrev.pop() elif delNodesNext and len(delNodesNext)>=2: delNodesNext.pop() delNodesNext.pop() elif delNodesPrev and len(delNodesPrev)==1: delNodesPrev.pop() if delNodesNext and len(delNodesNext)==1: delNodesNext.pop() elif delNodesNext and len(delNodesNext)==1: delNodesNext.pop() delNodes = delNodesPrev + delNodesNext # Удаляем переводы строк map(lambda x: xmlNodeBody.removeChild(x), delNodes) #print xmlNodeBody.toprettyxml().encode("UTF-8") # Удаляем области for term in map(lambda x: xmlNodeBody.removeChild(x), deletesNodes): if not term: self.setError(_('Can not remove DNS zone "%s"')%zoneName+\ " " + _("in config file %s")%self.nameConfigFile) return False # Запись файла text = self.getConfig().encode("UTF-8") return self.writeInConfig(text) def deleteAllZones(self, functPrintSuccess=False): """Удаляет зоны из конфигурационного файла bind Если в конфигурационном файле зон нет, ошибка не происходит. """ # Флаг включения метода печати успешного удаления зоны flagPrintSuccess = False if functPrintSuccess and callable(functPrintSuccess): flagPrintSuccess = True if self.getError(): return False deletesNodes = [] # Получаем ноды зон xmlZonesNames = self._getAllXMLZonesNames() if not xmlZonesNames: return True for nodeZone in xmlZonesNames: nodeValue = nodeZone.firstChild.nodeValue.lower() if '"."' in nodeValue: continue elif '"localhost"' in nodeValue: continue elif '"127.in-addr.arpa"' in nodeValue: continue else: nodeValue = nodeValue.encode("UTF-8") # Название зоны nameZ = nodeValue.rpartition('"')[0].partition('"')[2] deletesNodes.append((nodeZone.parentNode.parentNode,nameZ)) # Удаление областей xmlNodeBody = self.docObj.getNodeBody() nextNode = lambda x: x.nextSibling prevNode = lambda x: x.previousSibling delNodesNext = [] delNodesPrev = [] for node, zoneNameTmp in deletesNodes: nNode = node nNode = nextNode(nNode) while nNode and self.docObj.getTypeField(nNode)=="br": delNodesNext.append(nNode) nNode = nextNode(nNode) pNode = node pNode = prevNode(pNode) while pNode and self.docObj.getTypeField(pNode)=="br": delNodesPrev.append(pNode) pNode = prevNode(pNode) # Оставляем два перевода строки сверху if delNodesPrev and len(delNodesPrev)>=2: delNodesPrev.pop() delNodesPrev.pop() elif delNodesNext and len(delNodesNext)>=2: delNodesNext.pop() delNodesNext.pop() elif delNodesPrev and len(delNodesPrev)==1: delNodesPrev.pop() if delNodesNext and len(delNodesNext)==1: delNodesNext.pop() elif delNodesNext and len(delNodesNext)==1: delNodesNext.pop() delWorkNodes = delNodesPrev + delNodesNext delNodes = [] for delNode in delWorkNodes: if not delNode in delNodes: delNodes.append(delNode) # Удаляем переводы строк map(lambda x: xmlNodeBody.removeChild(x), delNodes) #print xmlNodeBody.toprettyxml().encode("UTF-8") # Удаляем области for delNode, zoneName in deletesNodes: if xmlNodeBody.removeChild(delNode): # Печатаем сообщение о успешном удалении зоны if flagPrintSuccess: functPrintSuccess(zoneName) else: self.setError(_('Can not remove DNS zone "%s"')%zoneName+\ " " + _("in config file %s")%self.nameConfigFile) return False # Запись файла text = self.getConfig().encode("UTF-8") return self.writeInConfig(text) def createZone(self, clVars, zoneName, zoneType, zoneMasters=[]): """Создает зону в файле конфигурации bind""" if self.getError(): return False textZone = self.getTextZone(clVars, zoneName, zoneType, zoneMasters) if not textZone: return False bindObj = cl_profile.bind(textZone) xmlNodeBodyNewZone = bindObj.docObj.getNodeBody() namesAreaNew = xpath.Evaluate(\ "child::area/child::caption/child::name", xmlNodeBodyNewZone) splNameNewNode =\ namesAreaNew[0].firstChild.nodeValue.replace("{","").split('"') splNameNewNode = splNameNewNode[1] if self.getXMLZoneToName(splNameNewNode): self.setError(_('DNS zone "%s" exists')%splNameNewNode) return False # Объединение конфигураций self.join(bindObj) # Запись файла text = self.getConfig().encode("UTF-8") return self.writeInConfig(text) def notFoundZones(self, zoneNames): """Поиск зон в конфигурационном файле выдает список не найденнных зон""" existsZones = self.getAllNamesZones() return sorted(list(set(zoneNames)-set(existsZones))) def createExclZones(self, clVars, zoneNames, zoneType, zoneMasters=[]): """Создает зоны в файле конфигурации bind Будут созданы зоны которых нет в конфигурационном файле zoneNames - зоны которые будут созданы Не проверяется наличие зон в конфигурационном файле """ if self.getError(): return False # Находим зоны отсутствующие в конфигурационном файле zonesNames = self.notFoundZones(zoneNames) if not zonesNames: return True flagError = False textConfig = "" for zoneName in zonesNames: textZone = self.getTextZone(clVars, zoneName, zoneType, zoneMasters) if not textZone: flagError = True break textConfig += textZone + "\n" if flagError: return False bindObj = cl_profile.bind(textConfig) # Объединение конфигураций self.join(bindObj) # Запись файла text = self.getConfig().encode("UTF-8") return self.writeInConfig(text) class servDns(shareLdap): """Методы сервиса DNS""" # Прямые зоны relFwdDN = 'ou=Forward' # Обратные зоны relRevDN = 'ou=Reverse' relServDN = 'ou=DNS' ldifFileBase = "/usr/lib/calculate/calculate-server/ldif/dns_base.ldif" # интервал времени для обновления зоны в секундах или # число + (M - минуты, H - часы, D - дни, W - недели) zoneRefresh = "8H" # интервал времени после неудачного обновления зоны zoneUpdateRetry = "2H" # интервал времени устаревания данных зоны на вторичных # DNS серверах в случае невозможности соединения с главным сервером zoneExpiry = "2W" # интервал времени хранения данных неудачных запросов к другим серверам # DNS серверам zoneMinimum = "2H" def __init__(self): shareLdap.__init__(self) # DN сервиса self.relDN = self.addDN(self.relServDN,self.ServicesDN) # DN прямых зон, относительно базового DN self.relForwardDN = self.addDN(self.relFwdDN, self.relDN) # DN обратных зон, относительно базового DN self.relReverseDN = self.addDN(self.relRevDN, self.relDN) @adminConnectLdap def _searchLdapDNSub(self, name, relDN, attr, retAttr=None): """Находит DN в LDAP ишет во всех ветках""" DN = self.addDN(relDN,self.baseDN) searchScope = ldap.SCOPE_SUBTREE searchFilter = "%s=%s" %(attr,name) retrieveAttributes = retAttr resSearch = self.ldapObj.ldapSearch(DN, searchScope, searchFilter, retrieveAttributes) return resSearch def _getRelZoneBaseDN(self, zoneName, opt="ZonesDN"): """Выдает opt='ZonesDN' - DN хранения зон opt='ouZonesDN' - ('ou=Forvard' или 'ou=Reverse') opt='ZonesDN' - DN зоны opt='isFwdZone' - (прямая зона - True, обратная зона - False) выдаваемые DN хранения зон и DN зоны относительно базового DN """ if opt=="ZonesDN" or opt=="ZoneDN": listRelZones = (self.relForwardDN, self.relReverseDN) elif opt=="ouZonesDN": listRelZones = (self.relFwdDN, self.relRevDN) elif opt=="isFwdZone": listRelZones = (True, False) if ".in-addr.arpa" in zoneName: # реверсивная зона relZoneDN = listRelZones[1] else: # прямая зона relZoneDN = listRelZones[0] if opt=="ZonesDN" or opt=="ouZonesDN" or opt=="isFwdZone": return relZoneDN elif opt=="ZoneDN": return "zoneName=%s,%s" %(zoneName, relZoneDN) return False def isForwardZone(self, zoneName): """Прямая зона - True, обратная False Проверка на .in-addr.arpa """ return self._getRelZoneBaseDN(zoneName, "isFwdZone") def getRelZonesDN(self, zoneName): """Относительный DN хранения зон""" return self._getRelZoneBaseDN(zoneName) def getRelZoneDN(self, zoneName): """Относительный DN хранения зоны""" return self._getRelZoneBaseDN(zoneName, "ZoneDN") def getOUZonesDN(self, zoneName): """ou хранения зон ou=Forvard или ou=Reverse""" return self._getRelZoneBaseDN(zoneName, "ouZonesDN") def searchZoneInLDAP(self, zoneName): """Находим DNS зону в LDAP""" relZonesDN = self.getRelZonesDN(zoneName) resSearch = self.searchLdapDN(zoneName, relZonesDN, "zoneName") return resSearch def searchAllZonesInLDAP(self): """Информация о всех зонах в LDAP (для cl-info)""" resSearchFwd = self.searchLdapDN('*', self.relForwardDN, "zoneName", ["zoneName"]) resSearchRev = self.searchLdapDN('*', self.relReverseDN, "zoneName", ["zoneName"]) return map (lambda x: x[0][1]['zoneName'][0],\ resSearchFwd + resSearchRev) def searchAllRecordInZone(self, zoneName): """Информация о всех записях в LDAP зоне (для cl-info) Кроме SOA записи (имя домена @) """ relZonesDN = self.getRelZonesDN(zoneName) relZoneDN = self.addDN("zoneName=%s"%zoneName,relZonesDN) resSearch = self.searchLdapDN("*", relZoneDN,"relativeDomainName") if resSearch: resSearch = filter(lambda x:\ not x[0][1]["relativeDomainName"][0]=="@",\ resSearch) return resSearch def searchAllDomainNamesInLDAP(self, domainName): """Находит узел описания домена (если домен @ - это описание зоны) Ищет в LDAP, выдает все записи """ hostName, spl, zoneName = domainName.partition(".") relZoneDN = self.getRelZoneDN(zoneName) if hostName == "*": hostName = r"\*" resSearch = self.searchLdapDN(hostName, relZoneDN, "relativeDomainName") return resSearch def searchDomainNameInLDAP(self, domainName): """Находит узел описания домена (если домен @ - это описание зоны) Ищет в LDAP, выдает все записи кроме CNAME """ resSearch = self.searchAllDomainNamesInLDAP(domainName) if resSearch: resSearch=filter(lambda x: not x[0][1].has_key("cNAMERecord"),\ resSearch) return resSearch def searchCNameInLDAP(self, domainName): """Находит узел CNAME Ищет в LDAP """ resSearch = self.searchAllDomainNamesInLDAP(domainName) if resSearch: resSearch=filter(lambda x: x[0][1].has_key("cNAMERecord"),\ resSearch) return resSearch def searchIPinForward(self, ip): """Находит узлы с данным ip в прямых зонах Ищет в LDAP """ resSearch = self._searchLdapDNSub(ip, self.relForwardDN, "aRecord") if resSearch: resSearch = filter(lambda x:\ not x[0][1]["relativeDomainName"][0]=="@",\ resSearch) return resSearch def searchHostsForIPinForward(self, ip): """Находит имена хостов на основании ip в прямой зоне""" hostNames = [] foundNames = self.searchIPinForward(ip) if foundNames: for aRecord in foundNames: relDomainNames = aRecord[0][1]['relativeDomainName'] zoneName = aRecord[0][1]['zoneName'][0] domainNames = map(lambda x:"%s.%s"%(x,zoneName),relDomainNames) hostNames += domainNames return hostNames def searchHostinReverse(self, host): """Находит узлы с данным именем хоста в обратных зонах Ищет в LDAP """ hostDot = "%s."%host resSearch = self._searchLdapDNSub(hostDot,self.relReverseDN,"pTRRecord") if resSearch: resSearch = filter(lambda x:\ not x[0][1]["relativeDomainName"][0]=="@",\ resSearch) return resSearch def searchIPForHostInReverse(self, host): """Находит ip на основании имени хоста в обратной зоне""" IPs = [] foundIPs = self.searchHostinReverse(host) if foundIPs: for ptrRecord in foundIPs: lastOctIPs = ptrRecord[0][1]['relativeDomainName'] zoneName = ptrRecord[0][1]['zoneName'][0] domainNames = map(lambda x:"%s.%s"%(x,zoneName),lastOctIPs) for name in domainNames: listOctRev = name.rpartition(".in-addr.arpa")[0].split(".") listOctRev.reverse() IPs.append(".".join(listOctRev)) return IPs def createSlaveZone(self, zoneName, zoneMasters): """Создание подчинненной DNS зоны в конфигурационном файле zoneName - имя зоны zoneMasters - ip адреса мастер DNS серверов (список) """ # Ишем зону в LDAP if self.searchZoneInLDAP(zoneName): self.printERROR(_("DNS zone %s exists in LDAP")%zoneName) return False # Ищем зону в тексте конфига objTxtZone = dnsTxt() if zoneName in objTxtZone.getAllNamesZones(): self.printERROR(_("DNS zone %s exists in /etc/bind/named.conf")\ %zoneName) return False if not self.stopServices(['dns']): return False if not objTxtZone.createZone(False, zoneName, "slave", zoneMasters): return False if not self.startServices(['dns'],False): return False self.printOK(_("Appended DNS slave zone %s")%zoneName) return True def createMasterZone(self, zoneName, nameServer="", emailAddr="", namesServers = [], serialNumber="1", refresh=zoneRefresh, updateRetry=zoneUpdateRetry, expiry=zoneExpiry, minimum=zoneMinimum, ip="", mxList=[]): """Создание первичной DNS зоны в конфигурационном файле и в LDAP Параметры: nameServer - имя первичного мастер сервера DNS зоны emailAddr - адрес электронной почты человека управляющего зоной serialNumber - порядковый номер от 0 до 4.294.967.295 refresh - интервал времени для обновления зоны в секундах или число + (M - минуты, H - часы, D - дни, W - недели) updateRetry - интервал времени после неудачного обновления зоны expiry - интервал времени устаревания данных зоны на вторичных DNS серверах в случае невозможности соединения с главным сервером minimum - интервал времени хранения данных неудачных запросов к другим DNS серверам namesServers - авторитативные DNS-серверы для данного домена. Количество записей типа NS должно точно соответствовать количеству DNS-серверов, обслуживающих домен и включать все DNS-серверы, указанные в домене ip - адрес зоны mx - MX записи для зоны """ # Добавление зоны в конфигурационный файл ldapParser = iniLdapParser() part = "dns" self.clVars.Set("ld_dns_dn",ldapParser.getVar(part,"DN"),True) self.clVars.Set("ld_dns_pw",ldapParser.getVar(part,"PASS"),True) # Ишем зону в LDAP if self.searchZoneInLDAP(zoneName): self.printERROR(_("DNS zone %s exists in LDAP")%zoneName) return False # Ищем зону в тексте конфига objTxtZone = dnsTxt() if zoneName in objTxtZone.getAllNamesZones(): self.printERROR(_("DNS zone %s exists in /etc/bind/named.conf")\ %zoneName) return False if not self.stopServices(['dns']): return False if not objTxtZone.createZone(self.clVars, zoneName, "master"): return False # Создание зоны в LDAP (создается объект переменных и соединение с LDAP) if not self.createZoneInLDAP(zoneName, nameServer, emailAddr, serialNumber, refresh, updateRetry, expiry, minimum, namesServers, ip, mxList): return False if not self.startServices(['dns'],False): return False self.printOK(_("Appended DNS master zone %s")%zoneName) return True def deleteZone(self, zoneName): """Удаление DNS зоны из конфигурационного файла и LDAP""" if not self.stopServices(['dns']): return False flagDeleteZone = False objTxtZone = dnsTxt() if zoneName in objTxtZone.getAllNamesZones(): if not objTxtZone.deleteZone(zoneName): return False flagDeleteZone = True else: self.printWARNING(_("Can not found zone %s in \ /etc/bind/named.conf")%zoneName) # Если зона найдена в LDAP удаляем ее if self.searchZoneInLDAP(zoneName): # Удаление зоны из LDAP if not self.deleteZoneInLDAP(zoneName): return False flagDeleteZone = True else: self.printWARNING(_("Can not found zone %s in LDAP")\ %zoneName) if not self.startServices(['dns'],False): return False if flagDeleteZone: self.printOK(_("Deleted DNS zone %s")%zoneName) else: self.printERROR(_("Can not found DNS zone %s")%zoneName) return False return True def createZoneInLDAP(self, zoneName, nameServer, emailAddr, serialNumber, refresh, updateRetry, expiry, minimum, namesServers, ip, mxList): """Создание DNS зоны в LDAP Параметры: nameServer - имя первичного мастер сервера DNS зоны emailAddr - адрес электронной почты человека управляющего зоной serialNumber - порядковый номер от 0 до 4.294.967.295 refresh - интервал времени для обновления зоны в секундах или число + (M - минуты, H - часы, D - дни, W - недели) updateRetry - интервал времени после неудачного обновления зоны expiry - интервал времени устаревания данных зоны на вторичных DNS серверах в случае невозможности соединения с главным сервером minimum - интервал времени хранения данных неудачных запросов к другим DNS серверам namesServers - авторитативные DNS-серверы для данного домена. Количество записей типа NS должно точно соответствовать количеству DNS-серверов, обслуживающих домен и включать все DNS-серверы, указанные в домене ip - адрес зоны mx - MX записи для зоны """ if not nameServer: self.printERROR(_("Empty name server in SOA-record in zone %s")\ %zoneName) return False if not namesServers: self.printERROR(_("Empty autoritative names servers in SOA-record\ in zone %s")%zoneName) return False # Метод добавляющий в конце текста точку если ее нет addDot = lambda x: (len(x)>0 and x[-1]!="." and "%s."%x) or x # Имя первичного DNS сервера nameServerDot = addDot(nameServer) if not emailAddr: self.printERROR(_("Empty email address in SOA-record in zone %s")\ %zoneName) return False # Почтовый адрес администратора зоны emailAddrDot = ".".join(addDot(emailAddr).split("@")) # Регулярное выражение для проверки интервалов времени на корректность regTime = re.compile("^\d+[smhdwSMHDW]?$") sOATimeParams = [refresh,updateRetry,expiry,minimum] # Проверка корректности значений интервалов времени incorrectTimeValues = filter(lambda x: not regTime.search(x),\ sOATimeParams) if incorrectTimeValues: self.printERROR(_("Values %s incorrect in SOA-record")\ %", ".join(incorrectTimeValues)) return False # Добавление точки если необходимо в каждое имя DNS сервера # Имена авторитативных DNS серверов для зоны namesServersDot = map(lambda x: addDot(x), namesServers) # Получение текста sOA записи sOARecord = " ".join([nameServerDot,emailAddrDot,serialNumber] +\ sOATimeParams) # Ищем зону в LDAP (создается соединение и объект переменных) if self.searchZoneInLDAP(zoneName): self.printERROR(_("DNS zone %s exists in LDAP")%zoneName) return False baseDN = self.clVars.Get("ld_dns_dn") if ".in-addr.arpa" in zoneName: if ip: self.printERROR(_("Can not add A-record %s")%ip + " " +\ _("in reverse zone %s")%zoneName) return False if mxList: self.printERROR(_("Can not add MX-records %s")\ %", ".join(mxList) +\ " " + _("in reverse zone %s")%zoneName) return False # реверсивная зона zoneBaseDN = "zoneName=%s,%s,%s" %(zoneName, self.relRevDN, baseDN) else: # прямая зона zoneBaseDN = "zoneName=%s,%s,%s" %(zoneName, self.relFwdDN, baseDN) zoneBaseEntry = [('objectclass', ['top','dNSZone']), ('relativeDomainName', [zoneName]), ('zoneName',[zoneName])] zoneBaseErrorMessage = _("Can not add in LDAP DNS zone %s") %zoneName if not self.addEntry(zoneBaseDN, zoneBaseEntry, zoneBaseErrorMessage): return False zoneDomainDN = self.addDN("relativeDomainName=@",zoneBaseDN) zoneDomainErrorMessage = _("Can not add SOA-record in zone %s")%zoneName zoneDomainEntry = [('objectclass', ['top','dNSZone']), ('relativeDomainName', ["@"]), ('zoneName',[zoneName]), ('sOARecord',[sOARecord]), ('nSRecord',namesServersDot)] if ip: zoneDomainEntry += [('aRecord',ip)] if mxList: mxListDot = map(lambda x: addDot(x), mxList) mxValues = map(lambda x: "%s %s" %(x*10+10, mxListDot[x]),\ range(len(mxListDot))) zoneDomainEntry += [('mXRecord', mxValues)] if not self.addEntry(zoneDomainDN, zoneDomainEntry, zoneDomainErrorMessage): return False return True def deleteZoneInLDAP(self, zoneName): """Удаление зоны из LDAP""" # При поиске зоны создается объект переменных и соединение LDAP if not self.searchZoneInLDAP(zoneName): self.printERROR(_("Can not found DNS zone %s in LDAP")%zoneName) return False relDelDN = self.getRelZoneDN(zoneName) # Удаление зоны ret = self.deleteDN(relDelDN) if not ret: return False return True def delRecordDnsServer(self, options, printWarning=True): """Удаляет запись в DNS""" # Проверим установлен ли сервис dns if not self.isServiceSetup("dns"): return False optKeys = options.keys() incompKeys = ["host","ip"] if set(incompKeys)<=set(optKeys): self.printERROR(_('Command line option "--host" (A-record) \ incompatible with option "--ip" (PTR-record)')) return False # Флаг MX - записи flagDeleteMX = False if options.has_key('mx'): flagDeleteMX = True # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) domainName = "" ip = "" typeRec = "" if options.has_key('host'): # Доменное имя (имя включающее домен) typeRec = "a" domainName = delDot(options['host'].lower()) # Имя хоста, имя зоны hostName, spl, zoneName = domainName.partition(".") if not zoneName: self.printERROR(_("Domain name %s incorrectly")%domainName) return False elif options.has_key('ip'): if flagDeleteMX: self.printERROR(_('Command line option "--mx" (MX-record) \ incompatible with option "--ip" (PTR-record)')) return False # ip адрес typeRec = "ptr" ip = options['ip'] if "," in ip or not self.isCorrectStringNet(ip, False): self.printERROR(_("IP address %s incorrectly")%ip) return False ret = False if typeRec == "a": foundDomain = self.searchDomainNameInLDAP(domainName) foundDomainCName = self.searchCNameInLDAP(domainName) if not foundDomainCName and not foundDomain: self.printERROR(_("Record %s not exists in LDAP")%domainName) return False if foundDomain: foundIP = foundDomain[0][0][1]['aRecord'][0] elif foundDomainCName: foundCName = foundDomainCName[0][0][1]['cNAMERecord'][0] typeRec = "cname" # Если MX запись if flagDeleteMX: # Удаляем MX запись из A записи if foundDomain: if not foundDomain[0][0][1].has_key('mXRecord'): self.printERROR(\ _("Can not found MX-records in A-record %s"%domainName)) return False # Имя хоста, имя зоны hostName, spl, zoneName = domainName.partition(".") if not zoneName: self.printERROR(\ _("Domain name %s incorrectly")%domainName) return False # Удаляем все MX записи в A записи ret = self.modMXRecord(hostName, domainName, zoneName, True, []) # Увеличиваем на 1 серийный номер зоны if not self.incrementSerialNumberZone(zoneName): return False else: # Удаляем A запись или CNAME запись ret = self.deleteDNSRecord(domainName) elif typeRec == "ptr": ipSpl = ip.split(".") ipSpl.reverse() # Имя домена обратной зоны domainNamePTR = "%s.in-addr.arpa" %".".join(ipSpl) foundDomain = self.searchDomainNameInLDAP(domainNamePTR) if not foundDomain: self.printERROR(_("PTR-record %s not exists in LDAP")%domainName) return False foundDomainName = foundDomain[0][0][1]['pTRRecord'][0] # Удаляем PTR запись ret = self.deleteDNSRecord(domainNamePTR) if not ret: return False if flagDeleteMX: pass elif typeRec == "a": self.printSUCCESS(_("Deleted A-record from LDAP")) self.printSUCCESS("%s --> %s"%(domainName,foundIP)) self.printSUCCESS("") if printWarning: # ip имещюиеся в обратной зоне для этого хоста IPWithHosts = self.searchIPForHostInReverse(domainName) if IPWithHosts: self.printWARNING(_("DNS has the following PTR-records")) for ip in IPWithHosts: self.printWARNING("%s --> %s"%(ip,domainName)) self.printWARNING("") elif typeRec == "ptr": self.printSUCCESS(_("Deleted PTR-record from LDAP")) self.printSUCCESS("%s --> %s"%(ip, delDot(foundDomainName))) self.printSUCCESS("") if printWarning: # Хосты имеющие этот IP в прямой зоне hostsWithIP = self.searchHostsForIPinForward(ip) if hostsWithIP: self.printWARNING(_("DNS has the following A-records")) for host in hostsWithIP: self.printWARNING("%s --> %s"%(host,ip)) self.printWARNING("") elif typeRec == "cname": self.printSUCCESS(_("Deleted CNAME-record from LDAP")) self.printSUCCESS("%s --> %s"%(domainName,foundCName)) self.printSUCCESS("") return True def isForwardName(self, name): """Проверка может ли имя являтся именем в прямой зоне""" forward = True # Проверка на сеть splName = name.split(".") for octet in splName: flagInt = True try: int(octet) except: flagInt = False if flagInt: forward = False break return forward def delZoneDnsServer(self, options): """Удаляет зону из DNS""" # Проверим установлен ли сервис dns if not self.isServiceSetup("dns"): return False # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) # Имя зоны zoneName = "" if options.has_key('n'): zoneName = delDot(options["n"].lower()) if not zoneName: self.printERROR(_('Incorrect zone name')) self.printERROR(_('Error in command line option "-n"')) return False # Проверка на прямую зону forwardZone = self.isForwardName(zoneName) # Обратная зона if not forwardZone: network, spl, netmask = zoneName.rpartition("/") if not netmask == "24" or \ not self.isCorrectStringNet(zoneName): self.printERROR(_('Incorrect network %s for reverse zone')\ %zoneName) self.printWARNING(_("Example network for reverse zone") +\ " :") self.printWARNING('"-n 192.168.0.0/24"') return False dataIP = self.getDomainAndZoneFromIP(network) if not dataIP: self.printERROR(_("IP address %s incorrectly")%network) return False hostName, domainName, zoneName = dataIP if not zoneName: self.printERROR(_("Not enough command line option %s")%"-n") return False if options.has_key('ip') or options.has_key('mx'): # Получение данных зоны из LDAP zoneData = self.searchAllDomainNamesInLDAP("@.%s"%zoneName) if not zoneData: self.printERROR(_("Can not found SOA-record in zone %s")\ %zoneName) return False # Удаление A записи if options.has_key('ip'): if not zoneData[0][0][1].has_key('aRecord'): self.printERROR(_("Can not found A-records in zone %s")\ %zoneName) return False if options.has_key('mx'): if not zoneData[0][0][1].has_key('mXRecord'): self.printERROR(\ _("Can not found MX-records in zone %s")\ %zoneName) return False relZoneDN = self.getRelZoneDN(zoneName) modAttrs =[(ldap.MOD_DELETE, 'aRecord', None)] DN = self.addDN("relativeDomainName=@", relZoneDN) if not self.modAttrsDN(DN, modAttrs): self.printERROR(\ _("Can not delete A-records for zone %s")\ %zoneName) return False self.printSUCCESS(_("Deleted A-records for zone %s")%zoneName) ret = True # Удаление MX записей if options.has_key('mx'): if not zoneData[0][0][1].has_key('mXRecord'): self.printERROR(_("Can not found MX-records in zone %s")\ %zoneName) return False # Удаляем все MX записи в записи зоны ret = self.modMXRecord("@", zoneName, zoneName, True, []) # Увеличиваем на 1 серийный номер зоны if not self.incrementSerialNumberZone(zoneName): return False return ret else: # Удаляем зону return self.deleteZone(zoneName) def addZoneDnsServer(self, options): """Добавляет зону в DNS""" # Проверим установлен ли сервис dns if not self.isServiceSetup("dns"): return False optKeys = options.keys() minKeys = [] # Тип зоны по умолчанию zoneType = "master" # Флаг указывающий - мастер зона flagZoneMaster = True # Тип зоны if "t" in optKeys: # Тип зоны (master/slave) zoneType = options["t"] if zoneType == "master": minKeys = ["n", "server"] flagZoneMaster = True elif zoneType == "slave": minKeys = ["t", "n","servers"] flagZoneMaster = False else: self.printERROR(_("Zone type %s unsupported")%zoneType) self.printWARNING(_("Supported zone types: %s")\ %", ".join(["master","slave"])) return False if not set(minKeys)<=set(optKeys): notFoundKeys = list(set(minKeys)-set(optKeys)) notFoundKeys = map(lambda x: len(x)>1 and '"--%s"'%x or '"-%s"'%x,\ notFoundKeys) self.printERROR(_("Not enough command line options: %s")\ %", ".join(notFoundKeys)) return False # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) # Имя зоны zoneName = "" forwardZone = True if options.has_key('n'): zoneName = delDot(options["n"].lower()) if not zoneName: self.printERROR(_('Incorrect zone name')) self.printERROR(_('Error in command line option "-n"')) return False # Проверка на прямую зону forwardZone = self.isForwardName(zoneName) # Обратная зона if forwardZone: # Проверка на имя хоста в LDAP if self.searchAllDomainNamesInLDAP(zoneName): self.printERROR(_("Found record %s in LDAP")%zoneName) return False else: # Проверка на недопустимые ключи для обратной зоны # ip зоны для обратной зоны недопустим if options.has_key('ip'): self.printERROR(_('Command line option "--ip" \ incompatible with reverse DNS zone %s')%zoneName) return False # MX записи для обратной зоны недопустимы if options.has_key('mx'): self.printERROR(_('Command line option "--mx" \ incompatible with reverse DNS zone %s')%zoneName) return False network, spl, netmask = zoneName.rpartition("/") if not netmask == "24" or \ not self.isCorrectStringNet(zoneName): self.printERROR(_('Incorrect network %s for reverse zone')\ %zoneName) self.printWARNING(_("Example network for reverse zone") +\ " :") self.printWARNING('"-n 192.168.0.0/24"') return False netSpl = network.split(".") netSpl.pop() netSpl.reverse() # Имя обратной зоны zoneName = "%s.in-addr.arpa" %".".join(netSpl) # Ищем зону # Ишем зону в LDAP if self.searchZoneInLDAP(zoneName): self.printERROR(_("DNS zone %s exists in LDAP")%zoneName) return False # Ищем зону в тексте конфига objTxtZone = dnsTxt() if zoneName in objTxtZone.getAllNamesZones(): self.printERROR(_("DNS zone %s exists in /etc/bind/named.conf")\ %zoneName) return False # ip зоны zoneIP = "" if options.has_key('ip'): zoneIP = options["ip"] if "," in zoneIP or \ not self.isCorrectStringNet(zoneIP, False): self.printERROR(_("IP address %s incorrectly")%zoneIP) return False # Почтовые серверы для зоны zoneListMX = [] if options.has_key('mx'): zoneListMX = map(lambda x: delDot(x.lower()),\ options['mx'].split(",")) zoneListMX = self.unicList(zoneListMX) if not self.checkMXDomains(zoneListMX): return False # Все авторитативные сервера зоны, в случае slаve зоны # ip авторитативных серверов хранения зоны namesServers = [] if options.has_key('servers'): namesServers = options['servers'].split(",") # Проверка на ip if not flagZoneMaster: if not self.isCorrectStringNet(options['servers'], False): self.printERROR(_('Incorrect autoritatives servers IP')) self.printERROR(_('Error in command line option \ "--servers"')) self.printWARNING(_('Example:')) self.printWARNING('--servers 192.168.0.1,192.168.0.2') return False else: flagErrorNs = False for ns in namesServers: if self.isCorrectStringNet(ns, False): flagErrorNs = True break if flagErrorNs: self.printERROR(_('Incorrect autoritatives servers names')) self.printERROR(_('Error in command line option \ "--servers"')) self.printWARNING(_('Example:')) self.printWARNING('--servers ns.domain.ru,ns1.domain.ru') return False # Мастер зона if flagZoneMaster: # Предупреждение о необходимости создания A записей для MX записей warningsMX = [] # Авторитативный сервер nameServer = "" if options.has_key('server'): nameServer = delDot(options["server"].lower()) if self.isCorrectStringNet(nameServer, False): self.printERROR(_('Incorrect autoritative server')) self.printERROR(_('Error in command line option \ "--server"')) self.printWARNING(_('Example:')) self.printWARNING('--server ns.domain.com') return False if not nameServer: self.printERROR(_('Incorrect autoritative server name')) self.printERROR(_('Error in command line option \ "--server"')) return False # Добавляем мастер сервер в имена авторитативаных серверов if not nameServer in namesServers: namesServers.insert(0, nameServer) # Имя хоста, имя зоны nsHostName, spl, nsZoneName = nameServer.partition(".") # ip авторитативного сервера ipserver = "" if nameServer == zoneName or nsZoneName == zoneName or\ (self.searchZoneInLDAP(nsZoneName) and\ not self.searchDomainNameInLDAP(nameServer)): if not options.has_key('ipserver'): self.printERROR(_('Not found A-record for "%s" \ (master server DNS)')%nameServer) self.printERROR(_('Not enough command line option \ "--ipserver"')) return False else: if nameServer == zoneName and zoneIP: self.printERROR(_("The same zone name and name of \ the primary authoritative server for the zone")) self.printERROR(_('We do not need the option "--ip"')) return False ipserver = options["ipserver"] if "," in ipserver or \ not self.isCorrectStringNet(ipserver, False): self.printERROR(_("IP address %s incorrectly")%ipserver) return False else: if options.has_key('ipserver'): if self.searchZoneInLDAP(nsZoneName) and\ self.searchDomainNameInLDAP(nameServer): self.printERROR(_('Command line option "--ipserver" \ is not needed, as the host name "%s" found in the DNS server')%nameServer) else: self.printERROR(_('Command line option "--ipserver" \ is not needed, as the host name "%s" does not belong to the existing zones on \ this DNS server')%nameServer) return False # Почтовый адрес администратора зоны # по умолчанию email = "%s@%s"%("root",zoneName) if options.has_key('email'): email = options['email'] # refresh - интервал времени для обновления зоны # update - интервал времени после неудачного обновления зоны # expiry - интервал времени устаревания данных зоны # minimum - интервал времени хранения данных неудачных запросов zoneTimeIntervals = {'refresh':self.zoneRefresh, 'update':self.zoneUpdateRetry, 'expiry':self.zoneExpiry, 'minimum':self.zoneMinimum} for nameOpt in zoneTimeIntervals.keys(): valueOpt = zoneTimeIntervals[nameOpt] locals()[nameOpt] = valueOpt if options.has_key(nameOpt): valueOpt = options[nameOpt] locals()[nameOpt] = valueOpt.upper() if not self.checkTimeValue(locals()[nameOpt]): self.printERROR(\ _('Incorrect command line options "--%s')\ %nameOpt + " " + '%s"'%valueOpt) return False if forwardZone: if nameServer == zoneName and ipserver: zoneIP = ipserver # создание основной зоны (прямая зона) if not self.createMasterZone(zoneName, nameServer, email, namesServers, "1", locals()['refresh'], locals()['update'], locals()['expiry'], locals()['minimum'], zoneIP, zoneListMX): return False # Добавление localhost.имя_зоны optionsLocalhost = {"autoptr":"off","t":"a", "host":"localhost.%s"%zoneName, "ip":"127.0.0.1"} if not self.addRecordDnsServer(optionsLocalhost): return False # Предупреждение о добавлении A записей для MX записей зоны # Находим список хостов которые необходимо добавить ARecordsForMX = self.getNotFoundRecords(zoneListMX) if ARecordsForMX: warningsMX=[_("For some MX-records not found PTR-records"), _("Create A-records for hostnames: %s")\ %", ".join(ARecordsForMX)] else: # создание основной зоны (обратная зона) if not self.createMasterZone(zoneName, nameServer, email, namesServers, "1", locals()['refresh'], locals()['update'], locals()['expiry'], locals()['minimum']): return False # Создание обратной зоны в случае необходимости if ipserver: dataIP = self.getDomainAndZoneFromIP(ipserver) if not dataIP: self.printERROR(_("IP address %s incorrectly")%ipserver) return False tmpHostName, domainNamePTR, zoneNameReverse = dataIP if not self.searchZoneInLDAP(zoneNameReverse): # Добавляем обратную зону if not self.createMasterZone(zoneNameReverse, nameServer, email,namesServers, "1", locals()['refresh'], locals()['update'], locals()['expiry'], locals()['minimum']): return False if not nameServer == zoneName: # Добавление A записи для первичного DNS сервера optionsR = {"autoptr":"off","t":"a","host":nameServer, "ip":ipserver} if not self.addRecordDnsServer(optionsR): return False foundReverseDomain =self.searchDomainNameInLDAP(domainNamePTR) if foundReverseDomain: zoneName = foundReverseDomain[0][0][1]['zoneName'][0] relativeDomainName = \ foundReverseDomain[0][0][1]['relativeDomainName'][0] pTRRecord = foundReverseDomain[0][0][1]['pTRRecord'][0] # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x,\ y.split("."))) reverseHost = delDot(pTRRecord) listOctRev = \ zoneName.rpartition(".in-addr.arpa")[0].split(".") listOctRev.reverse() reverseIp = ".".join(listOctRev +[relativeDomainName]) self.printWARNING(_("Can not add PTR-record in LDAP")) self.printWARNING(_("PTR-record exists")) self.printWARNING("%s --> %s"%(reverseIp,reverseHost)) self.printWARNING("") else: # Добавление PTR записи для первичного DNS сервера optionsR = {"t":"ptr", "host":nameServer, "ip":ipserver} if not self.addRecordDnsServer(optionsR): return False if warningsMX: for warning in warningsMX: self.printWARNING(warning) # Slave зона else: # Не нужные ключи командной строки notCmdKey = list(set(optKeys) - set(minKeys)) if notCmdKey: # Добавляем кавычки и -- addQ = lambda y: map(lambda x:\ len(x)>1 and '"--%s"'%x or '"-%s"'%x, y) self.printERROR(_("Incorrect command line options %s")\ %", ".join(addQ(notCmdKey))) return False if not self.createSlaveZone(zoneName, namesServers): return False return True def modARecord(self, hostName, domainName, zoneName, otherIP, newIP): """Изменение IP A записи (прямая зона)""" relZoneDN = self.getRelZoneDN(zoneName) modAttrs = [(ldap.MOD_REPLACE, 'aRecord', newIP)] DN = self.addDN("relativeDomainName=%s"\ %hostName, relZoneDN) if not self.modAttrsDN(DN, modAttrs): self.printERROR(\ _("Can not modify IP address in A-record %s")\ %domainName) return False self.printSUCCESS(_("Modified A-record %s")%domainName) self.printSUCCESS("%s --> %s"%(domainName, newIP)) self.printSUCCESS("") return True def modMXRecord(self, hostName, domainName, zoneName, foundMX, mxServers): """Изменение или создание MX записи (прямая зона)""" # Метод добавляющий в конце текста точку если ее нет addDot = lambda x: (len(x)>0 and x[-1]!="." and "%s."%x) or x relZoneDN = self.getRelZoneDN(zoneName) modAttrs = [] if foundMX: modAttrs =[(ldap.MOD_DELETE, 'mXRecord', None)] i = 0 for mxServer in mxServers: i += 10 mxString = "%s %s" %(i, addDot(mxServer)) modAttrs.append((ldap.MOD_ADD, 'mXRecord', mxString)) DN = self.addDN("relativeDomainName=%s"%hostName, relZoneDN) if not self.modAttrsDN(DN, modAttrs): if hostName == "@": if mxServers: self.printERROR(_("Can not modify MX hosts in zone %s")\ %zoneName) else: self.printERROR(\ _("Can not delete all MX-records in zone %s")\ %zoneName) else: if mxServers: self.printERROR(_("Can not modify MX hosts in A-record %s")\ %domainName) else: self.printERROR(\ _("Can not delete all MX-records in A-record %s")\ %domainName) return False if hostName == "@": if mxServers: self.printSUCCESS(_("Modified MX hosts in zone %s")\ %zoneName) for mxServer in mxServers: self.printSUCCESS("%s --> %s"%(domainName, mxServer)) self.printSUCCESS("") else: self.printSUCCESS(_("Deleted all MX-records in zone %s")\ %zoneName) else: if mxServers: self.printSUCCESS(_("Modified MX hosts in A-record %s")\ %domainName) for mxServer in mxServers: self.printSUCCESS("%s --> %s"%(domainName, mxServer)) self.printSUCCESS("") else: self.printSUCCESS(_("Deleted all MX-records in A-record %s")\ %domainName) return True def modPTRRecord(self, ip, PTRHostName, PTRDomainName, PTRZoneName, newDomainName): """Изменяет доменное имя в PTR записи""" # Метод добавляющий в конце текста точку если ее нет addDot = lambda x: (len(x)>0 and x[-1]!="." and "%s."%x) or x relZoneDN = self.getRelZoneDN(PTRZoneName) modAttrs = [(ldap.MOD_REPLACE, 'pTRRecord',\ addDot(newDomainName))] DN = self.addDN("relativeDomainName=%s"\ %PTRHostName, relZoneDN) if not self.modAttrsDN(DN, modAttrs): self.printERROR(\ _("Can not modify domain name in PTR-record %s")\ %PTRDomainName) return False self.printSUCCESS(_("Modified PTR-record %s")%PTRDomainName) self.printSUCCESS("%s --> %s"%(ip, newDomainName)) self.printSUCCESS("") return True def modCNAMERecord(self, hostName, domainName, zoneName, newCname): """Изменяет указатель cname в CNAME записи""" # Метод добавляющий в конце текста точку если ее нет addDot = lambda x: (len(x)>0 and x[-1]!="." and "%s."%x) or x relZoneDN = self.getRelZoneDN(zoneName) modAttrs = [(ldap.MOD_REPLACE, 'cNAMERecord',\ addDot(newCname))] DN = self.addDN("relativeDomainName=%s" %hostName, relZoneDN) if not self.modAttrsDN(DN, modAttrs): self.printERROR(\ _("Can not modify cname in CNAME-record %s")%domainName) return False self.printSUCCESS(_("Modified CNAME-record %s")%domainName) self.printSUCCESS("%s --> %s"%(domainName, newCname)) self.printSUCCESS("") return True def movePTRRecord(self, domainName, otherIP, newIP): """Переносит PTR запись с одного ip на другой ip""" if not self.moveDNSReverseRecord(otherIP, newIP): self.printERROR(_("Can not modify IP address for PTR-record")) self.printERROR(_("Can not modify from")) self.printERROR("%s --> %s"%(otherIP,domainName)) self.printERROR(_("to")) self.printERROR("%s --> %s"%(newIP,domainName)) self.printERROR("") return False self.printSUCCESS(_("Modified PTR-record")) self.printSUCCESS("%s --> %s"%(newIP, domainName)) self.printSUCCESS("") return True def moveARecord(self, ip, domainName, newDomainName): """Переносит A запись с одного доменного имени на другое""" if not self.moveDNSForwardRecord(domainName,newDomainName): self.printERROR(\ _("Can not modify domain name for A-record")) self.printERROR(_("Can not modify from")) self.printERROR("%s --> %s"%(domainName,ip)) self.printERROR(_("to")) self.printERROR("%s --> %s"%(newDomainName,ip)) self.printERROR("") return False self.printSUCCESS(_("Modified A-record")) self.printSUCCESS("%s --> %s"%(newDomainName,ip)) self.printSUCCESS("") return True def moveCNAMERecord(self, oldCname, domainName, newDomainName): """Переносит A или CNAME запись с одного доменного имени на другое""" if not self.moveDNSForwardRecord(domainName,newDomainName): self.printERROR(\ _("Can not modify domain name for CNAME-record")) self.printERROR(_("Can not modify from")) self.printERROR("%s --> %s"%(domainName,oldCname)) self.printERROR(_("to")) self.printERROR("%s --> %s"%(newDomainName,oldCname)) self.printERROR("") return False self.printSUCCESS(_("Modified CNAME-record")) self.printSUCCESS("%s --> %s"%(newDomainName,oldCname)) self.printSUCCESS("") return True def modZoneDnsServer(self, options): """Модифицирует параметры зоны в DNS""" # Проверим установлен ли сервис dns if not self.isServiceSetup("dns"): return False # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) # Имя зоны zoneName = "" if options.has_key('n'): zoneName = delDot(options["n"].lower()) if not zoneName: self.printERROR(_('Incorrect zone name')) self.printERROR(_('Error in command line option "-n"')) return False # Проверка на прямую зону forwardZone = self.isForwardName(zoneName) # Обратная зона if not forwardZone: network, spl, netmask = zoneName.rpartition("/") if not netmask == "24" or \ not self.isCorrectStringNet(zoneName): self.printERROR(_('Incorrect network %s for reverse zone')\ %zoneName) self.printWARNING(_("Example network for reverse zone") +\ " :") self.printWARNING('"-n 192.168.0.0/24"') return False dataIP = self.getDomainAndZoneFromIP(network) if not dataIP: self.printERROR(_("IP address %s incorrectly")%network) return False hostName, domainName, zoneName = dataIP if not zoneName: self.printERROR(_("Not enough command line option %s")%"-n") return False # Ищем мастер зону в LDAP if not self.searchZoneInLDAP(zoneName): self.printERROR(_("Can not found master zone %s in LDAP")%zoneName) return False # Проверка на mx совместно с mxmod if options.has_key('mx') and options.has_key('mxmod'): self.printERROR('Command line option "-mx" is incompatible \ with option "--mxmod"') return False # MX серверы mxServers = [] if options.has_key('mx'): mxServers=map(lambda x: delDot(x.lower()), options['mx'].split(",")) mxServers = self.unicList(mxServers) # Переименование mx записи # modMxServers[0] - cтарая запись # modMxServers[1] - новая запись modMxServers = [] if options.has_key('mxmod'): modMxServers=map(lambda x: delDot(x.lower()),\ options['mxmod'].split(",")) modMxServers = self.unicList(modMxServers) if len(modMxServers)!=2: self.printERROR(_('Incorrect command line option "--mxmod"')) self.printWARNING(_("Example") + ":") self.printWARNING("--mxmod old.mail.host,new.mail.host") return False # ip зоны zoneIP = "" if options.has_key('ip'): zoneIP = options["ip"] if "," in zoneIP or \ not self.isCorrectStringNet(zoneIP, False): self.printERROR(_("IP address %s incorrectly")%zoneIP) return False # Получение данных зоны из LDAP zoneData = self.searchAllDomainNamesInLDAP("@.%s"%zoneName) if not zoneData: self.printERROR(_("Can not found SOA-record in zone %s")%zoneName) return False soaRecord = zoneData[0][0][1]['sOARecord'][0] nSRecords = zoneData[0][0][1]['nSRecord'] soaData = map(lambda x: delDot(x), soaRecord.split(" ")) if len(soaData)!=7: self.printERROR(_("Incorrect SOA-record in DNS zone %s")%zoneName) return False # Все авторитативные сервера зоны, в случае slаve зоны namesServers = map(lambda x: delDot(x), nSRecords) oldNamesServers = map(lambda x: delDot(x), nSRecords) # Изменяем ip зоны if zoneIP: addDot = lambda x: (len(x)>0 and x[-1]!="." and "%s."%x) or x relZoneDN = self.getRelZoneDN(zoneName) modAttrs = [] if zoneData[0][0][1].has_key('aRecord'): modAttrs =[(ldap.MOD_DELETE, 'aRecord', None)] modAttrs.append((ldap.MOD_ADD, 'aRecord', zoneIP)) DN = self.addDN("relativeDomainName=@", relZoneDN) if not self.modAttrsDN(DN, modAttrs): self.printERROR(_("Can not modify A-record in zone %s")\ %zoneName) return False self.printSUCCESS(_("Modified A-record in zone %s")%zoneName) self.printSUCCESS("%s --> %s"%(zoneName, zoneIP)) self.printSUCCESS("") # Изменяем MX записи if mxServers or modMxServers: flagFoundMX = False if zoneData[0][0][1].has_key('mXRecord'): flagFoundMX = True # Изменяем почтовый хост на другой почтовый хост if modMxServers: if not flagFoundMX: self.printERROR(_("Can not found MX-record in zone %s")\ %zoneName) return False # Находим нужную запись foundMxServers = map(lambda x: len(x.split(" "))==1\ and delDot(x) or delDot(x.split(" ")[1]),\ zoneData[0][0][1]['mXRecord']) oldMxHost = modMxServers[0] newMxHost = modMxServers[1] if not oldMxHost in foundMxServers: self.printERROR(_("Can not found MX host %s")\ %oldMxHost +" " + _("in zone %s")%zoneName) return False # Проверка наличия новой MX записи в A записи if newMxHost in foundMxServers: self.printERROR(_("MX host %s exists")\ %newMxHost +" " + _("in zone %s")%zoneName) return False # Проверка существования A записи для MX хоста if not self.checkMXDomains([newMxHost]): return False # Добавляемые MX хосты addMxServers = [] for foundMxServer in foundMxServers: if foundMxServer == oldMxHost: # Замена имени хоста addMxServers.append(newMxHost) else: addMxServers.append(foundMxServer) if not self.modMXRecord("@", zoneName, zoneName, flagFoundMX, addMxServers): return False # Заменяем почтовые хосты if mxServers: # Проверка существования A записей для MX хостов if not self.checkMXDomains(mxServers): return False if not self.modMXRecord("@", zoneName, zoneName, flagFoundMX, mxServers): return False if options.has_key('servers'): namesServers = options['servers'].split(",") flagErrorNs = False for ns in namesServers: if self.isCorrectStringNet(ns, False): flagErrorNs = True break if flagErrorNs: self.printERROR(_('Incorrect autoritatives servers names')) self.printERROR(_('Error in command line option "--servers"')) self.printWARNING(_('Example:')) self.printWARNING('--servers ns.domain.ru,ns1.domain.ru') return False # Авторитативный сервер nameServer = soaData[0] if options.has_key('server'): nameServer = delDot(options["server"].lower()) if self.isCorrectStringNet(nameServer, False): self.printERROR(_('Incorrect autoritative server')) self.printERROR(_('Error in command line option \ "--server"')) self.printWARNING(_('Example:')) self.printWARNING('--server ns.domain.com') return False if not nameServer: self.printERROR(_('Incorrect autoritative server name')) self.printERROR(_('Error in command line option \ "--server"')) return False # Добавляем мастер сервер в имена авторитативаных серверов if not nameServer in namesServers: namesServers.insert(0, nameServer) # Имя хоста, имя зоны nsHostName, spl, nsZoneName = nameServer.partition(".") # Поиск главного авторитативного сервера в зонах if self.searchZoneInLDAP(nsZoneName) and\ not self.searchDomainNameInLDAP(nameServer): self.printERROR(_("Can not found host name %s in LDAP")\ %nameServer) self.printWARNING(\ _("Add A-record %s (autoritative DNS server) in LDAP")\ %nameServer) return False # Почтовый адрес администратора зоны splEmail = soaData[1].partition(".") email = "%s@%s"%(splEmail[0], delDot(splEmail[2])) oldEmail = email if options.has_key('email'): email = options['email'] # Серийный номер зоны serialNumber = str(ctypes.c_uint32(int(soaData[2])).value + 1) # refresh - интервал времени для обновления зоны # update - интервал времени после неудачного обновления зоны # expiry - интервал времени устаревания данных зоны # minimum - интервал времени хранения данных неудачных запросов zoneTimeIntervals = {'refresh':soaData[3], 'update':soaData[4], 'expiry':soaData[5], 'minimum':soaData[6]} for nameOpt in zoneTimeIntervals.keys(): valueOpt = zoneTimeIntervals[nameOpt] locals()[nameOpt] = valueOpt if options.has_key(nameOpt): valueOpt = options[nameOpt] locals()[nameOpt] = valueOpt.upper() if not self.checkTimeValue(locals()[nameOpt]): self.printERROR(_('Incorrect command line options "--%s')\ %nameOpt + " " + '%s"'%valueOpt) return False # Метод добавляющий в конце текста точку если ее нет addDot = lambda x: (len(x)>0 and x[-1]!="." and "%s."%x) or x sOAList = [addDot(nameServer), addDot(".".join(email.split("@"))), serialNumber, locals()['refresh'], locals()['update'], locals()['expiry'], locals()['minimum']] optKeys = options.keys() if len(optKeys)>1: sOARecord = " ".join(sOAList) relZoneDN = self.getRelZoneDN(zoneName) modAttrs = [(ldap.MOD_REPLACE, 'sOARecord', sOARecord)] if options.has_key('server') or options.has_key('servers'): # Добавляем мастер сервер в имена авторитативаных серверов if not nameServer in namesServers: namesServers.insert(0, nameServer) modAttrs.append((ldap.MOD_DELETE, 'nSRecord', None)) modAttrs.append((ldap.MOD_ADD, 'nSRecord',\ map(lambda x: addDot(x), namesServers))) DN = self.addDN("relativeDomainName=@", relZoneDN) if not self.modAttrsDN(DN, modAttrs): self.printERROR(_("Can not modify new SOA-record for zone %s \ in LDAP")%zoneName) return False # Результат исполнения для пользователя # Изменен ли главный сервер авторизации if nameServer != soaData[0]: self.printSUCCESS(_("Modified master autoritative DNS server")) # Изменен ли почтовый адрес администратора зоны if addDot(".".join(oldEmail.split("@"))) !=\ addDot(".".join(email.split("@"))): self.printSUCCESS(_("Modified email administrator zone")) # Изменены ли авторитативные DNS сервера зоны if set(oldNamesServers) != set(namesServers): self.printSUCCESS(\ _("Modified all autoritative DNS servers for zone")) # Вывод модифицированных параметров времени for nameOpt in zoneTimeIntervals.keys(): valueOld = zoneTimeIntervals[nameOpt] valueNew = locals()[nameOpt] if valueOld != valueNew: self.printSUCCESS(_("Modified %s")%nameOpt) else: self.printERROR(_("Can not found command line options")) return False self.printOK(_('Modified zone "%s"')%zoneName) return True def modRecordDnsServer(self, options, hostOrIP, checkDHCPConfig=False): """Модифицирует запись в DNS""" # Проверим установлен ли сервис dns if not self.isServiceSetup("dns"): return False # Опция force if "f" in options.keys(): checkDHCPConfig = False # Проверка на имя хоста вместе с ip if options.has_key('ip') and options.has_key('host'): self.printERROR('Command line option "--host" is incompatible \ with option "--ip"') return False # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) # модификация другой записи A -> PTR, PTR -> A modOther = True if options.has_key('automod'): autoMod = options['automod'] if autoMod == "on": modOther = True elif autoMod == "off": modOther = False else: self.printERROR(_('Command line option "--automod %s" \ incorrect, use "--automod on" or "--automod off"')%autoMod) return False # По умолчанию прямой тип записи typeRec = "a" if options.has_key('t'): # Тип модифицируемой записи typeRec = options['t'].lower() supportTypes = ("a","ptr","cname","mx") if not typeRec in supportTypes: self.printERROR(_("Record type %s unsupported")%typeRec) self.printWARNING(_("Supported record types: %s")\ %", ".join(supportTypes)) return False # Проверка на mx совместно с mxmod if options.has_key('mx') and options.has_key('mxmod'): self.printERROR('Command line option "-mx" is incompatible \ with option "--mxmod"') return False # Добавляем кавычки и -- addQ = lambda y: map(lambda x: len(x)>1 and '"--%s"'%x or '"-%s"'%x, y) # Ключи опций optKeys = options.keys() # Обязательные опции requiredOpt = [] # Необязательные опции optionalOpt = [] # Проверки совместимых опций if "mxmod" in optKeys: requiredOpt = ["mxmod"] optionalOpt = {"t":["mx"]} typeRec = "mx" elif "mx" in optKeys: requiredOpt = ["mx"] optionalOpt = {"t":["mx"]} typeRec = "mx" elif "host" in optKeys: requiredOpt = ["host"] optionalOpt = {"t":["a","ptr"],"automod":["on","off"]} if typeRec == "cname": # Изменения только в прямой зоне в случае CNAME записи modOther = False requiredOpt = ["host"] optionalOpt = {"t":["cname"]} elif "ip" in optKeys: requiredOpt = ["ip"] optionalOpt = {"t":["a","ptr"],"automod":["on","off"]} elif "cname" in optKeys: # Изменения только в прямой зоне в случае CNAME записи modOther = False requiredOpt = ["cname"] optionalOpt = {"t":["cname"]} typeRec = "cname" else: self.printERROR(_("Incorrect command line options %s")\ %", ".join(addQ(optKeys))) return False # Проверка обязательных опций if not set(requiredOpt)<=set(optKeys): notFoundReqOpt = list(set(requiredOpt)-set(optKeys)) self.printERROR(_('Can not found required command line options %s')\ %", ".join(addQ(notFoundReqOpt))) return False if "f" in options.keys(): optionalOpt['f'] = options['f'] # Проверка необязательных опций errorOptionalOpt = False for key, value in optionalOpt.items(): if key in optKeys and value: if not options[key] in value: errorOptionalOpt = True break if errorOptionalOpt: self.printERROR(\ _('Optional comand line option %s it has a wrong value')\ %addQ([key])[0]) self.printWARNING(_('Valid values are the options %s')\ %addQ([key])[0] + " " + '(%s)'\ % (" "+_("or")+" ").join(map(lambda x: '"%s"'%x, value))) return False # Проверка лишних опций unnecessaryOpt = list(set(optKeys)-set(requiredOpt+optionalOpt.keys())) if unnecessaryOpt: self.printERROR(_("Exists unnecessary command line options %s")\ %",".join(addQ(unnecessaryOpt))) return False mxServers = [] if options.has_key('mx'): # Оключаем модификацию обратной зоны modOther = False # Почтовые серверы для доменного имени if typeRec == "ptr": self.printERROR(_('Command line option "--mx" \ incompatible with PTR-record (option "-t")')) return False if typeRec == "cname": self.printERROR(_('Command line option "--mx" \ incompatible with CNAME-record (option "-t")')) return False mxServers=map(lambda x: delDot(x.lower()), options['mx'].split(",")) mxServers = self.unicList(mxServers) # Переименование mx записи # modMxServers[0] - cтарая запись # modMxServers[1] - новая запись modMxServers = [] if options.has_key('mxmod'): # Отключаем модификацию обратной зоны modOther = False # Почтовые cерверы для доменного имени if typeRec == "ptr": self.printERROR(_('Command line option "--mxmod" \ incompatible with PTR-record (option "-t")')) return False if typeRec == "cname": self.printERROR(_('Command line option "--mxmod" \ incompatible with CNAME-record (option "-t")')) return False modMxServers=map(lambda x: delDot(x.lower()),\ options['mxmod'].split(",")) modMxServers = self.unicList(modMxServers) if len(modMxServers)!=2: self.printERROR(_('Incorrect command line option "--mxmod"')) self.printWARNING(_("Example") + ":") self.printWARNING("--mxmod old.mail.host,new.mail.host") return False cnameServer = "" if options.has_key('cname'): # Оключаем модификацию обратной зоны modOther = False # Доменное имя (имя включающее домен) cnameServer = delDot(options['cname'].lower()) # Имя хоста, имя зоны tmpHostName, spl, tmpZoneName = cnameServer.partition(".") if not tmpZoneName or not self.isForwardName(cnameServer): self.printERROR(_("Domain name %s incorrectly")%cnameServer) return False newDomainName = "" newHostName = "" newZoneName = "" # Новая запись является CNAME foundNewCnameRecord = False if options.has_key('host'): # Доменное имя (имя включающее домен) newDomainName = delDot(options['host'].lower()) # Имя хоста, имя зоны newHostName, spl, newZoneName = newDomainName.partition(".") if not newZoneName or not self.isForwardName(newDomainName): self.printERROR(_("Domain name %s incorrectly")%newDomainName) return False if typeRec == "a" or typeRec == "cname": # Проверка существования нового домена foundNewDomain = self.searchDomainNameInLDAP(newDomainName) if not foundNewDomain: foundNewDomain = self.searchCNameInLDAP(newDomainName) foundNewCnameRecord = True if foundNewDomain: if foundNewCnameRecord: self.printERROR(_("CNAME-record %s exists in LDAP")\ %newDomainName) self.printERROR("%s --> %s"%(newDomainName,\ delDot(foundNewDomain[0][0][1]['cNAMERecord'][0]))) else: self.printERROR(_("A-record %s exists in LDAP")\ %newDomainName) self.printERROR("%s --> %s"\ %(newDomainName, foundNewDomain[0][0][1]['aRecord'][0])) self.printERROR("") return False # Проверка существования обратной записи if modOther and typeRec != "cname": newIPs = self.searchIPForHostInReverse(newDomainName) if newIPs: self.printERROR(_("Found records in reverse zone")) for IP in newIPs: self.printERROR("%s --> %s"%(IP,newDomainName)) self.printERROR("") return False elif typeRec == "ptr": # Проверка существования обратной записи newIPs = self.searchIPForHostInReverse(newDomainName) if newIPs: self.printERROR(_("Found records in reverse zone")) for IP in newIPs: self.printERROR("%s --> %s"%(IP,newDomainName)) self.printERROR("") return False if modOther: # Проверка существования нового домена foundNewDomain = self.searchDomainNameInLDAP(newDomainName) if not foundNewDomain: foundNewDomain = self.searchCNameInLDAP(newDomainName) foundNewCnameRecord = True if foundNewDomain: if foundNewCnameRecord: self.printERROR(_("CNAME-record %s exists in LDAP")\ %newDomainName) self.printERROR("%s --> %s"%(newDomainName,\ delDot(foundNewDomain[0][0][1]['cNAMERecord'][0]))) else: self.printERROR(_("A-record %s exists in LDAP")\ %newDomainName) self.printERROR("%s --> %s"\ %(newDomainName, foundNewDomain[0][0][1]['aRecord'][0])) self.printERROR("") return False newIP = "" newZoneNameIP = "" newHostNameIP = "" if options.has_key('ip'): if typeRec == "cname": self.printERROR('Command line option "-t cname" \ is incompatible with option "--ip"') return False # newIP адрес newIP = options['ip'] if "," in newIP or not self.isCorrectStringNet(newIP, False): self.printERROR(_("IP address %s incorrectly")%newIP) return False # Если установлен сервис DHCP и # включено чтение конфигурационного файла DHCP сервиса if checkDHCPConfig and self.isServiceSetup("dhcp", False): # Создаем DHCP объект servDhcpObj = servDhcp() # Проверка на попадание в динамические адреса DHCP if not servDhcpObj.isCorrectStaticIP(newIP): return False if typeRec == "ptr": dataNewIP = self.getDomainAndZoneFromIP(newIP) if not dataNewIP: self.printERROR(_("IP address %s incorrectly")%newIP) return False newHostNameIP, newDomainNameIP, newZoneNameIP = dataNewIP # Проверка существования нового ip foundNewIp = self.searchAllDomainNamesInLDAP(newDomainNameIP) if foundNewIp: self.printERROR(_("IP address %s exists in LDAP")%newIP) self.printERROR("%s --> %s"%(newIP,\ delDot(foundNewIp[0][0][1]['pTRRecord'][0]))) self.printERROR("") return False # Проверка существования обратной записи if modOther: newDomainNames = self.searchHostsForIPinForward(newIP) if newDomainNames: self.printERROR(_("Found records in forward zone")) for host in newDomainNames: self.printERROR("%s --> %s"%(host,newIP)) self.printERROR("") return False elif typeRec == "a": newDomainNames = self.searchHostsForIPinForward(newIP) if newDomainNames: self.printERROR(_("Found records in forward zone")) for host in newDomainNames: self.printERROR("%s --> %s"%(host,newIP)) self.printERROR("") return False if modOther: dataNewIP = self.getDomainAndZoneFromIP(newIP) if not dataNewIP: self.printERROR(_("IP address %s incorrectly")%newIP) return False newHostNameIP, newDomainNameIP, newZoneNameIP = dataNewIP # Проверка существования нового ip foundNewIp=self.searchAllDomainNamesInLDAP(newDomainNameIP) if foundNewIp: self.printERROR(_("IP address %s exists in LDAP")%newIP) self.printERROR("%s --> %s"%(newIP,\ delDot(foundNewIp[0][0][1]['pTRRecord'][0]))) self.printERROR("") return False # Имена изменяемых зон namesZones = [] # Флаг True - hostOrIP является хостом hostInForwardZone = self.isForwardName(hostOrIP) ip = "" domainName = "" hostName = "" zoneName = "" domainNamePTR = "" hostNamePTR = "" zoneNamePTR = "" # hostOrIP является именем хоста if hostInForwardZone: domainName = delDot(hostOrIP.lower()) # Имя хоста, имя зоны hostName, spl, zoneName = domainName.partition(".") if not zoneName: self.printERROR(_("Domain name %s incorrectly")%domainName) return False # Поиск модифицируемой записи в DNS # Поиск основной записи if typeRec == "a": # найдена CNAME запись? if self.searchCNameInLDAP(domainName): self.printERROR(_("CNAME-record %s exists in LDAP")\ %domainName) self.printWARNING(_('Use command line option "-t cname"')) return False foundMain = self.searchDomainNameInLDAP(domainName) if not foundMain: self.printERROR(_("Record %s not exists in LDAP")\ %domainName) return False otherIP = delDot(foundMain[0][0][1]['aRecord'][0]) # Поиcк в обратной зоне в случае необходимости if modOther: dataIP = self.getDomainAndZoneFromIP(otherIP) if not dataIP: self.printERROR(_("IP address %s incorrectly")%otherIP) return False otherHostName, otherDomain, otherZoneName = dataIP foundOther = self.searchAllDomainNamesInLDAP(otherDomain) if not foundOther: self.printERROR(_("PTR-record %s not exists in LDAP")\ %otherDomain) return False # Проверка на соответствие имени хоста if domainName!=delDot(foundOther[0][0][1]['pTRRecord'][0]): self.printERROR(_("Found PTR-record %s in LDAP")\ %otherDomain) self.printERROR("%s --> %s"%(otherIP,\ delDot(foundOther[0][0][1]['pTRRecord'][0]))) self.printERROR("") return False # Изменяем в двух зонах if newIP: # Если изменяется IP # Изменение IP A записи (прямая зона) if not self.modARecord(hostName, domainName, zoneName, otherIP, newIP): return False # Изменение IP PTR записи (обратная зона) if not self.movePTRRecord(domainName, otherIP, newIP): return False # Изменяемая прямая зона namesZones.append(zoneName) # Изменяемая обратная зона namesZones.append(otherZoneName) # Изменяемая обратная зона namesZones.append(newZoneNameIP) else: # Если изменяется доменное имя # Изменение доменного имени A записи (прямая зона) if not self.moveARecord(otherIP, domainName, newDomainName): return False # Изменение доменного имени PTR записи (обратная зона) if not self.modPTRRecord(otherIP, otherHostName, otherDomain, otherZoneName, newDomainName): return False # Изменяемая прямая зона namesZones.append(zoneName) # Изменяемая прямая зона namesZones.append(newZoneName) # Изменяемая обратная зона namesZones.append(otherZoneName) else: # Если не нужно модифицировать обратную запись if newIP: # Если изменяется IP # Изменение IP A записи (прямая зона) if not self.modARecord(hostName, domainName, zoneName, otherIP, newIP): return False # Изменяемая прямая зона namesZones.append(zoneName) else: # Если изменяется доменное имя # Изменение доменного имени A записи (прямая зона) if not self.moveARecord(otherIP, domainName, newDomainName): return False # Изменяемая прямая зона namesZones.append(zoneName) # Изменяемая прямая зона namesZones.append(newZoneName) elif typeRec == "ptr": IPs = self.searchIPForHostInReverse(domainName) if not IPs: self.printERROR(_("Can not found %s in reverse zone")\ %domainName) return False if len(IPs)>1: self.printERROR(_("Found multiple records in reverse zone")) for IP in IPs: self.printERROR("%s --> %s"%(IP,domainName)) self.printERROR("") return False ip = IPs[0] # Модификация otherIP = ip dataIP = self.getDomainAndZoneFromIP(ip) if not dataIP: self.printERROR(_("IP address %s incorrectly")%ip) return False hostNamePTR, domainNamePTR, zoneNamePTR = dataIP # Модификация otherZoneName = zoneNamePTR # Модификация otherHostName = hostNamePTR # Модификация otherDomainName = domainNamePTR foundMain = self.searchAllDomainNamesInLDAP(domainNamePTR) if not foundMain: self.printERROR(_("PTR-record %s not exists in LDAP")\ %domainNamePTR) return False # Поиcк в обратной зоне в случае необходимости if modOther: otherDomain = delDot(foundMain[0][0][1]['pTRRecord'][0]) foundOther = self.searchAllDomainNamesInLDAP(otherDomain) if not foundOther: self.printERROR(_("A-record %s not exists in LDAP")\ %otherDomain) return False # Проверка на соответствие ip хоста if ip != foundOther[0][0][1]['aRecord'][0]: self.printERROR(_("Found A-record %s in LDAP")\ %otherDomain) self.printERROR("%s --> %s"\ %(otherDomain, foundOther[0][0][1]['aRecord'][0])) self.printERROR("") return False # Модифицируем PTR запись # Изменяем в двух зонах if newIP: # Если изменяется IP # Изменение IP PTR записи (обратная зона) if not self.movePTRRecord(domainName, otherIP, newIP): return False # Изменение IP A записи (прямая зона) if not self.modARecord(hostName, domainName, zoneName, otherIP, newIP): return False # Изменяемая обратная зона namesZones.append(otherZoneName) # Изменяемая обратная зона namesZones.append(newZoneNameIP) # Изменяемая прямая зона namesZones.append(zoneName) else: # Если изменяется доменное имя # Изменение доменного имени PTR записи (обратная зона) if not self.modPTRRecord(otherIP, otherHostName, otherDomain, otherZoneName, newDomainName): return False # Изменение доменного имени A записи (прямая зона) if not self.moveARecord(otherIP, domainName, newDomainName): return False # Изменяемая обратная зона namesZones.append(otherZoneName) # Изменяемая прямая зона namesZones.append(zoneName) # Изменяемая прямая зона namesZones.append(newZoneName) else: if newIP: # Если изменяется IP # Изменение IP PTR записи (обратная зона) if not self.movePTRRecord(domainName, otherIP, newIP): return False # Изменяемая обратная зона namesZones.append(otherZoneName) # Изменяемая обратная зона namesZones.append(newZoneNameIP) else: # Если изменяется доменное имя # Изменение доменного имени PTR записи (обратная зона) if not self.modPTRRecord(otherIP, otherHostName, otherDomainName, otherZoneName, newDomainName): return False # Изменяемая обратная зона namesZones.append(otherZoneName) elif typeRec == "cname": foundMain = self.searchCNameInLDAP(domainName) if not foundMain: self.printERROR(_("CNAME-record %s not exists in LDAP")\ %domainName) return False # Изменяем cname указатель if cnameServer: if not self.modCNAMERecord(hostName, domainName, zoneName, cnameServer): return False # Изменяемая прямая зона namesZones.append(zoneName) # CNAME запись (изменяем имя домена) if newDomainName: oldCname = delDot(foundMain[0][0][1]['cNAMERecord'][0]) if not self.moveCNAMERecord(oldCname,domainName, newDomainName): return False # Изменяемая прямая зона namesZones.append(zoneName) # Изменяемая прямая зона namesZones.append(newZoneName) elif typeRec == "mx": # Поиск A записи foundMain = self.searchDomainNameInLDAP(domainName) if not foundMain: self.printERROR(_("Record %s not exists in LDAP")\ %domainName) return False flagFoundMX = False if foundMain[0][0][1].has_key('mXRecord'): flagFoundMX = True # Изменяем почтовый хост на другой почтовый хост if modMxServers: if not flagFoundMX: self.printERROR(\ _("Can not found MX-record in A-record %s")\ %domainName) return False # Находим нужную запись foundMxServers = map(lambda x: len(x.split(" "))==1\ and delDot(x) or delDot(x.split(" ")[1]),\ foundMain[0][0][1]['mXRecord']) oldMxHost = modMxServers[0] newMxHost = modMxServers[1] if not oldMxHost in foundMxServers: self.printERROR(_("Can not found MX host %s")\ %oldMxHost +" " + _("in A-record %s")%domainName) return False # Проверка наличия новой MX записи в A записи if newMxHost in foundMxServers: self.printERROR(_("MX host %s exists")\ %newMxHost +" " + _("in A-record %s")%domainName) return False # Проверка существования A записи для MX хоста if not self.checkMXDomains([newMxHost]): return False # Добавляемые MX хосты addMxServers = [] for foundMxServer in foundMxServers: if foundMxServer == oldMxHost: # Замена имени хоста addMxServers.append(newMxHost) else: addMxServers.append(foundMxServer) if not self.modMXRecord(hostName, domainName, zoneName, flagFoundMX, addMxServers): return False # Изменяемая прямая зона namesZones.append(zoneName) # Заменяем почтовые хосты if mxServers: # Проверка существования A записей для MX хостов if not self.checkMXDomains(mxServers): return False if not self.modMXRecord(hostName, domainName, zoneName, flagFoundMX, mxServers): return False # Изменяемая прямая зона namesZones.append(zoneName) # hostOrIP является ip else: if "," in hostOrIP or not self.isCorrectStringNet(hostOrIP, False): self.printERROR(_("IP address %s incorrectly")%hostOrIP) return False ip = hostOrIP # Модификация otherIP = ip if typeRec == "cname": self.printERROR(_('IP address %s')%ip + " " +\ _('incompatible with CNAME-record (option "-t")')) return False if "cname" in optKeys: self.printERROR(_('IP address %s')%ip + " " +\ _('incompatible with CNAME-record (option "--cname")')) return False # Поиск модифицируемой записи в DNS # Поиск основной записи if typeRec == "ptr": dataIP = self.getDomainAndZoneFromIP(ip) if not dataIP: self.printERROR(_("IP address %s incorrectly")%ip) return False hostNamePTR, domainNamePTR, zoneNamePTR = dataIP # Модификация otherZoneName = zoneNamePTR # Модификация otherHostName = hostNamePTR # Модификация otherDomainName = domainNamePTR foundMain = self.searchAllDomainNamesInLDAP(domainNamePTR) if not foundMain: self.printERROR(_("PTR-record %s not exists in LDAP")\ %domainNamePTR) return False otherDomain = delDot(foundMain[0][0][1]['pTRRecord'][0]) # Модификация domainName = otherDomain # Модификация hostName, spl, zoneName = otherDomain.partition(".") # Поиcк в обратной зоне в случае необходимости if modOther: foundOther = self.searchAllDomainNamesInLDAP(otherDomain) if not foundOther: self.printERROR(_("A-record %s not exists in LDAP")\ %otherDomain) return False # Проверка на соответствие ip хоста if ip != foundOther[0][0][1]['aRecord'][0]: self.printERROR(_("Found A-record %s in LDAP")\ %otherDomain) self.printERROR("%s --> %s"\ %(otherDomain, foundOther[0][0][1]['aRecord'][0])) self.printERROR("") return False # Модифицируем PTR запись # Изменяем в двух зонах if newIP: # Если изменяется IP # Изменение IP PTR записи (обратная зона) if not self.movePTRRecord(domainName, otherIP, newIP): return False # Изменение IP A записи (прямая зона) if not self.modARecord(hostName, domainName, zoneName, otherIP, newIP): return False # Изменяемая обратная зона namesZones.append(otherZoneName) # Изменяемая обратная зона namesZones.append(newZoneNameIP) # Изменяемая прямая зона namesZones.append(zoneName) else: # Если изменяется доменное имя # Изменение доменного имени PTR записи (обратная зона) if not self.modPTRRecord(otherIP, otherHostName, otherDomain, otherZoneName, newDomainName): return False # Изменение доменного имени A записи (прямая зона) if not self.moveARecord(otherIP, domainName, newDomainName): return False # Изменяемая обратная зона namesZones.append(otherZoneName) # Изменяемая прямая зона namesZones.append(zoneName) # Изменяемая прямая зона namesZones.append(newZoneName) else: if newIP: # Если изменяется IP # Изменение IP PTR записи (обратная зона) if not self.movePTRRecord(domainName, otherIP, newIP): return False # Изменяемая обратная зона namesZones.append(otherZoneName) # Изменяемая обратная зона namesZones.append(newZoneNameIP) else: # Если изменяется доменное имя # Изменение доменного имени PTR записи (обратная зона) if not self.modPTRRecord(otherIP, otherHostName, otherDomainName, otherZoneName, newDomainName): return False # Изменяемая обратная зона namesZones.append(otherZoneName) elif typeRec == "a": domainNames = self.searchHostsForIPinForward(ip) if not domainNames: self.printERROR(_("Can not found %s in forward zone")%ip) return False if len(domainNames)>1: self.printERROR(_("Found multiple records in forward zone")) for host in domainNames: self.printERROR("%s --> %s"%(host,ip)) self.printERROR("") return False domainName = domainNames[0] hostName, spl, zoneName = domainName.partition(".") # найдена CNAME запись? if self.searchCNameInLDAP(domainName): self.printERROR(_("CNAME-record %s exists in LDAP")\ %domainName) self.printWARNING(_('Use command line option "-t cname"')) return False foundMain = self.searchDomainNameInLDAP(domainName) if not foundMain: self.printERROR(_("Record %s not exists in LDAP")\ %domainName) return False # Поиcк в обратной зоне в случае необходимости if modOther: otherIP = delDot(foundMain[0][0][1]['aRecord'][0]) dataIP = self.getDomainAndZoneFromIP(otherIP) if not dataIP: self.printERROR(_("IP address %s incorrectly")%otherIP) return False otherHostName, otherDomain, otherZoneName = dataIP foundOther = self.searchAllDomainNamesInLDAP(otherDomain) if not foundOther: self.printERROR(_("PTR-record %s not exists in LDAP")\ %otherDomain) return False # Проверка на соответствие имени хоста if domainName!=delDot(foundOther[0][0][1]['pTRRecord'][0]): self.printERROR(_("Found PTR-record %s in LDAP")\ %otherDomain) self.printERROR("%s --> %s"%(otherIP,\ delDot(foundOther[0][0][1]['pTRRecord'][0]))) self.printERROR("") return False # Изменяем в двух зонах if newIP: # Если изменяется IP # Изменение IP A записи (прямая зона) if not self.modARecord(hostName, domainName, zoneName, otherIP, newIP): return False # Изменение IP PTR записи (обратная зона) if not self.movePTRRecord(domainName, otherIP, newIP): return False # Изменяемая прямая зона namesZones.append(zoneName) # Изменяемая обратная зона namesZones.append(otherZoneName) # Изменяемая обратная зона namesZones.append(newZoneNameIP) else: # Если изменяется доменное имя # Изменение доменного имени A записи (прямая зона) if not self.moveARecord(otherIP, domainName, newDomainName): return False # Изменение доменного имени PTR записи (обратная зона) if not self.modPTRRecord(otherIP, otherHostName, otherDomain, otherZoneName, newDomainName): return False # Изменяемая прямая зона namesZones.append(zoneName) # Изменяемая прямая зона namesZones.append(newZoneName) # Изменяемая обратная зона namesZones.append(otherZoneName) else: # Если не нужно модифицировать обратную запись if newIP: # Если изменяется IP # Изменение IP A записи (прямая зона) if not self.modARecord(hostName, domainName, zoneName, otherIP, newIP): return False # Изменяемая прямая зона namesZones.append(zoneName) else: # Если изменяется доменное имя # Изменение доменного имени A записи (прямая зона) if not self.moveARecord(otherIP, domainName, newDomainName): return False # Изменяемая прямая зона namesZones.append(zoneName) # Изменяемая прямая зона namesZones.append(newZoneName) elif typeRec == "mx": # Поиск A записи domainNames = self.searchHostsForIPinForward(ip) if len(domainNames)>1: self.printERROR(_("Found multiple records in forward zone")) for host in domainNames: self.printERROR("%s --> %s"%(host,ip)) self.printERROR("") return False domainName = domainNames[0] hostName, spl, zoneName = domainName.partition(".") foundMain = self.searchDomainNameInLDAP(domainName) if not foundMain: self.printERROR(_("Record %s not exists in LDAP")\ %domainName) return False flagFoundMX = False if foundMain[0][0][1].has_key('mXRecord'): flagFoundMX = True # Изменяем почтовый хост на другой почтовый хост if modMxServers: if not flagFoundMX: self.printERROR(\ _("Can not found MX-record in A-record %s")\ %domainName) return False # Находим нужную запись foundMxServers = map(lambda x: len(x.split(" "))==1\ and delDot(x) or delDot(x.split(" ")[1]),\ foundMain[0][0][1]['mXRecord']) oldMxHost = modMxServers[0] newMxHost = modMxServers[1] if not oldMxHost in foundMxServers: self.printERROR(_("Can not found MX host %s")\ %oldMxHost +" " + _("in A-record %s")%domainName) return False # Проверка существования A записи для MX хоста if not self.checkMXDomains([newMxHost]): return False # Добавляемые MX хосты addMxServers = [] for foundMxServer in foundMxServers: if foundMxServer == oldMxHost: # Замена имени хоста addMxServers.append(newMxHost) else: addMxServers.append(foundMxServer) if not self.modMXRecord(hostName, domainName, zoneName, flagFoundMX, addMxServers): return False # Изменяемая прямая зона namesZones.append(zoneName) # Заменяем почтовые хосты if mxServers: # Проверка существования A записей для MX хостов if not self.checkMXDomains(mxServers): return False if not self.modMXRecord(hostName, domainName, zoneName, flagFoundMX, mxServers): return False # Изменяемая прямая зона namesZones.append(zoneName) # Увеличение серийного номера измененных зон namesZones = list(set(namesZones)) flagError = False for nameZone in namesZones: # Увеличиваем на 1 серийный номер зоны if not self.incrementSerialNumberZone(nameZone): flagError = True break if flagError: return False return True def getDomainAndZoneFromIP(self, ip): """Получение имени хоста, домена, зоны из ip""" ipSpl = ip.split(".") ipSpl.reverse() # Имя обратного домена domainName = "%s.in-addr.arpa" %".".join(ipSpl) hostName, spl, zoneName = domainName.partition(".") if zoneName: return (hostName, domainName, zoneName) else: return False def moveDNSReverseRecord(self, oldIP, newIP): """Переносит запись c oldIP в запись с newIP (в обратной зоне)""" dataOldIP = self.getDomainAndZoneFromIP(oldIP) if not dataOldIP: self.printERROR(_("IP address %s incorrectly")%oldIP) return False oldHostName, oldDomainName, oldZoneName = dataOldIP dataNewIP = self.getDomainAndZoneFromIP(newIP) if not dataNewIP: self.printERROR(_("IP address %s incorrectly")%newIP) return False newHostName, newDomainName, newZoneName = dataNewIP return self.moveDNSForwardRecord(oldDomainName, newDomainName) def moveDNSForwardRecord(self, oldDomainName, newDomainName): """Переносит запись oldDomainName в newDomainName (в прямой зоне)""" # Имя нового хоста, имя новой зоны newHostName, spl, newZoneName = newDomainName.partition(".") # Ищем новую зону if not self.searchZoneInLDAP(newZoneName): self.printERROR(_("Can not found DNS zone %s in LDAP")%newZoneName) return False # Ищем старый хост foundOld = self.searchAllDomainNamesInLDAP(oldDomainName) if not foundOld: self.printERROR(_("Record %s not exists in LDAP")%oldDomainName) return False # Данные data = foundOld[0][0][1] data["zoneName"] = [newZoneName] data["relativeDomainName"] = [newHostName] domainEntry = data.items() # Добавляем новую запись baseDN = self.clVars.Get("ld_dns_dn") ouZonesDN = self.getOUZonesDN(newZoneName) zoneBaseDN = "zoneName=%s,%s,%s"%(newZoneName, ouZonesDN, baseDN) domainDN = self.addDN("relativeDomainName=%s" %newHostName,zoneBaseDN) # Сообщение в случае ошибки errorMessage = _('Can not add record "%s" in LDAP'%newDomainName) # Добавляем запись if not self.addEntry(domainDN, domainEntry, errorMessage): return False # Удаляем предыдущую запись if not self.deleteDNSRecord(oldDomainName): return False # Имя cтарого хоста, имя старой зоны oldHostName, spl, oldZoneName = oldDomainName.partition(".") namesZones = [oldZoneName, newZoneName] if namesZones[0] == namesZones[1]: namesZones.pop() flagError = False for nameZone in namesZones: # Увеличиваем на 1 серийный номер зоны if not self.incrementSerialNumberZone(nameZone): flagError = True break if flagError: return False return True def addRecordDnsServer(self, options, checkDHCPConfig=False): """Добавляет запись в DNS""" # Проверим установлен ли сервис dns if not self.isServiceSetup("dns"): return False optKeys = options.keys() # Опция force if "f" in optKeys: checkDHCPConfig = False # По умолчанию прямой тип записи typeRec = "a" if options.has_key('t'): # Тип добавлямой записи typeRec = options['t'].lower() supportTypes = ("a","ptr","cname") if not typeRec in supportTypes: self.printERROR(_("Record type %s unsupported")%typeRec) self.printWARNING(_("Supported record types: %s")\ %", ".join(supportTypes)) return False if typeRec == "cname": minKeys = ["cname","host"] else: minKeys = ["host","ip"] if not set(minKeys)<=set(optKeys): notFoundKeys = list(set(minKeys)-set(optKeys)) notFoundKeys = map(lambda x: len(x)>1 and '"--%s"'%x or '"-%s"'%x,\ notFoundKeys) self.printERROR(_("Not enough command line options: %s")\ %", ".join(notFoundKeys)) return False # Флаг автоматического создания PTR записи createPtr = True if options.has_key('autoptr'): if typeRec == "ptr": self.printERROR(_('Command line option "--autoptr" \ incompatible with type DNS record PTR (option "-t")')) return False if typeRec == "cname": self.printERROR(_('Command line option "--autoptr" \ incompatible with type DNS record CNAME (option "-t")')) return False autoPtr = options['autoptr'] if autoPtr == "on": createPtr = True elif autoPtr == "off": createPtr = False else: self.printERROR(_('Command line option "--autoptr %s" \ incorrect, use "--autoptr on" or "--autoptr off"')%autoPtr) return False # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) domainName = "" hostName = "" zoneName = "" if options.has_key('host'): # Доменное имя (имя включающее домен) domainName = delDot(options['host'].lower()) # Имя хоста, имя зоны hostName, spl, zoneName = domainName.partition(".") if not zoneName: self.printERROR(_("Domain name %s incorrectly")%domainName) return False cnDomainName = "" cnHostName = "" cnZoneName = "" if options.has_key('cname'): if options.has_key('ip'): self.printERROR(_('Command line option "--ip" incompatible \ with type DNS record CNAME (option "-t")')) return False if options.has_key('mx'): self.printERROR(_('Command line option "--mx" incompatible \ with type DNS record CNAME (option "-t")')) return False # Доменное каноническое имя (имя включающее домен) для CNAME cnDomainName = delDot(options['cname'].lower()) # Имя хоста, имя зоны cnHostName, spl, cnZoneName = cnDomainName.partition(".") if not cnZoneName: self.printERROR(_("Domain name %s incorrectly")%cnDomainName) return False ip = "" if options.has_key('ip'): # ip адрес ip = options['ip'] if "," in ip or not self.isCorrectStringNet(ip, False): self.printERROR(_("IP address %s incorrectly")%ip) return False # Если установлен сервис DHCP и # включено чтение конфигурационного файла DHCP сервиса if checkDHCPConfig and self.isServiceSetup("dhcp", False): # Создаем DHCP объект servDhcpObj = servDhcp() # Проверка на попадание в динамические адреса DHCP if not servDhcpObj.isCorrectStaticIP(ip): return False mxServers = [] if options.has_key('mx'): # Почтовые серверы для доменного имени if typeRec == "ptr": self.printERROR(_('Command line option "--mx" incompatible \ with type DNS record PTR (option "-t")')) return False mxServers = map(lambda x: delDot(x.lower()),\ options['mx'].split(",")) mxServers = self.unicList(mxServers) ret = False # Флаг создания A записи flagCreateARecord = False # Прямая запись DNS if typeRec == "a": ret = self.addDNSRecord(domainName, ip, mxServers) flagCreateARecord = ret if ret and createPtr: typeRec = "ptr" if typeRec == "ptr": ipSpl = ip.split(".") ipSpl.reverse() # Имя домена обратной зоны domainNamePTR = "%s.in-addr.arpa" %".".join(ipSpl) ret = self.addDNSRecord(domainNamePTR, domainName) if typeRec == "cname": ret = self.addCNameDNSRecord(domainName, cnDomainName) if not ret: if flagCreateARecord: # Удаляем A запись self.deleteDNSRecord(domainName) return False if typeRec == "a" or flagCreateARecord: self.printSUCCESS(_("Added A-record in LDAP")) self.printSUCCESS("%s --> %s"%(domainName,ip)) self.printSUCCESS("") if mxServers: self.printSUCCESS(_("Added MX-records in LDAP")) for mailServer in mxServers: self.printSUCCESS("%s --> %s"%(domainName, mailServer)) if typeRec == "ptr": self.printSUCCESS(_("Added PTR-record in LDAP")) self.printSUCCESS("%s --> %s"%(ip,domainName)) self.printSUCCESS("") if typeRec == "cname": self.printSUCCESS(_("Added CNAME-record in LDAP")) self.printSUCCESS("%s --> %s"%(domainName,cnDomainName)) self.printSUCCESS("") return True def addCNameDNSRecord(self, domainName, cnDomainName): """Добавляем CNAME DNS запись в LDAP domainName -> cnDomainName """ hostName, spl, zoneName = domainName.partition(".") cnHostName, spl, cnZoneName = cnDomainName.partition(".") # Поиск зоны if self.searchZoneInLDAP(cnZoneName): # Поиск имени хоста if not self.searchDomainNameInLDAP(cnDomainName): self.printERROR(_("Can not found A-record %s in LDAP")\ %cnDomainName) return False # Поиск зоны if not self.searchZoneInLDAP(zoneName): self.printERROR(_("Can not found DNS zone %s in LDAP")%zoneName) return False # Поиск CNAME записи findCName = self.searchCNameInLDAP(domainName) if findCName: self.printERROR(_("CNAME-record %s exists in LDAP")\ %domainName) cnameHosts = findCName[0][0][1]['cNAMERecord'] for cnameHost in cnameHosts: self.printERROR("%s --> %s"%(domainName,cnameHost)) self.printERROR("") return False # Метод добавляющий в конце текста точку если ее нет addDot = lambda x: (len(x)>0 and x[-1]!="." and "%s."%x) or x domainEntry = [('objectclass', ['top','dNSZone']), ('relativeDomainName', [hostName]), ('dNSClass', ['IN']), ('zoneName',[zoneName]), ('cNAMERecord',[addDot(cnDomainName)])] baseDN = self.clVars.Get("ld_dns_dn") ouZonesDN = self.getOUZonesDN(zoneName) zoneBaseDN = "zoneName=%s,%s,%s" %(zoneName, ouZonesDN, baseDN) domainDN = self.addDN("relativeDomainName=%s"%hostName,zoneBaseDN) errorMessage = _("Can not add CNAME-record in LDAP") # Добавляем запись для хоста if not self.addEntry(domainDN, domainEntry,errorMessage): return False # Увеличиваем на 1 серийный номер зоны if not self.incrementSerialNumberZone(zoneName): return False return True def checkTimeValue(self, timeValue): """Проверяет корректность переменной времени""" # разбиваем строку на символы charList = map(lambda x: timeValue[x:x+1], range(len(timeValue))) if not charList: return False # Проверяем последний символ на число value = timeValue try: int(charList[-1]) except: # Проверяем последний символ на допустимые символы # Проверка на наличие символов (минуты, часы, дни, недели) if not charList[-1] in ("M","H","D","W"): return False value = "".join(charList[:-1]) try: int(value) except: return False return True def getNotFoundRecords(self, namesServers): """Находит серверы из списка, которые должны быть созданы Результат состоит из доменных имен удовлетворяющим этому правилу (зона для доменного имени существует, доменного имени в ней нет) """ # Имена серверов которые могут находится в существующих зонах serversInZones = filter(lambda x:\ self.searchZoneInLDAP(x.partition(".")[2]),\ namesServers) notFoundServers = filter(lambda x:\ not self.searchDomainNameInLDAP(x),\ serversInZones) return notFoundServers def checkMXDomains(self, namesMailServers): """Проверяет каким MX хостам необходимы A записи""" notFoundMailServers = self.getNotFoundRecords(namesMailServers) if notFoundMailServers: self.printERROR(\ _("Can not found A-records for MX-records - %s")\ %", ".join(notFoundMailServers)) self.printWARNING(\ _("First, add the A-records required for MX-records")) return False return True def addDNSRecord(self, domainName, ipAddrOrHost, namesMailServers=[]): """Добавляем DNS запись в LDAP прямую или обратную""" hostName, spl, zoneName = domainName.partition(".") # При поиске зоны создается объект переменных и соединение LDAP if not self.searchZoneInLDAP(zoneName): self.printERROR(_("Can not found DNS zone %s in LDAP")%zoneName) return False if self.searchDomainNameInLDAP(domainName): self.printERROR(_("Record %s exists in LDAP")\ %domainName) return False # Поиск CNAME записи if self.searchCNameInLDAP(domainName): self.printERROR(_("CNAME-record %s exists in LDAP")\ %domainName) return False flagForward = self.isForwardZone(zoneName) # Метод добавляющий в конце текста точку если ее нет addDot = lambda x: (len(x)>0 and x[-1]!="." and "%s."%x) or x if flagForward: # Проверка существования A записей для MX хостов if not self.checkMXDomains(namesMailServers): return False namesMailServersDot = map(lambda x: addDot(x), namesMailServers) domainEntry = [('objectclass', ['top','dNSZone']), ('relativeDomainName', [hostName]), ('dNSClass', ['IN']), ('zoneName',[zoneName]), ('aRecord',[ipAddrOrHost])] mxValues=map(lambda x: "%s %s" %(x*10+10, namesMailServersDot[x]),\ range(len(namesMailServersDot))) if mxValues: # Добавляем MX записи domainEntry.append(('mXRecord', mxValues)) else: domainEntry = [('objectclass', ['top','dNSZone']), ('relativeDomainName', [hostName]), ('zoneName',[zoneName]), ('pTRRecord',[addDot(ipAddrOrHost)])] baseDN = self.clVars.Get("ld_dns_dn") ouZonesDN = self.getOUZonesDN(zoneName) zoneBaseDN = "zoneName=%s,%s,%s" %(zoneName, ouZonesDN, baseDN) domainDN = self.addDN("relativeDomainName=%s"%hostName,zoneBaseDN) if flagForward: errorMessage = _("Can not add A-record in LDAP") else: errorMessage = _("Can not add PTR-record in LDAP") # Добавляем запись для хоста if not self.addEntry(domainDN, domainEntry,errorMessage): return False # Увеличиваем на 1 серийный номер зоны if not self.incrementSerialNumberZone(zoneName): return False return True def deleteDNSRecord(self, domainName): """Удаляем DNS запись из LDAP""" hostName, spl, zoneName = domainName.partition(".") if not self.searchZoneInLDAP(zoneName): self.printERROR(_("Can not found DNS zone %s in LDAP")%zoneName) return False if not self.searchAllDomainNamesInLDAP(domainName): self.printERROR(_("Record %s not exists in LDAP")%domainName) return False relZoneDN = self.getRelZoneDN(zoneName) relDelDN = self.addDN("relativeDomainName=%s"%hostName,relZoneDN) # Удаление DNS записи ret = self.delDN(relDelDN) if not ret: return False # Увеличиваем на 1 серийный номер зоны if not self.incrementSerialNumberZone(zoneName): return False return True def incrementSerialNumberZone(self, zoneName): """Увеличение на единицу серийного номера зоны""" if not self.searchZoneInLDAP(zoneName): self.printERROR(_("Can not found DNS zone %s in LDAP")%zoneName) return False foundNames = self.searchDomainNameInLDAP("@.%s"%zoneName) if not foundNames: self.printERROR(_("Can not found SOA-record in DNS zone %s")\ %zoneName) return False sOARecord = foundNames[0][0][1]['sOARecord'][0] sOAList = sOARecord.split(" ") if len(sOAList)!=7: self.printERROR(_("Incorrect SOA-record in DNS zone %s")%zoneName) return False try: serialNumber = str(ctypes.c_uint32(int(sOAList[2])).value + 1) except: self.printERROR(_("Incorrect SOA-record in DNS zone %s")%zoneName) self.printERROR(_("Incorrect serial number %s in SOA-record")\ %str(sOAList[2])) return False sOAList[2] = serialNumber sOARecord = " ".join(sOAList) relZoneDN = self.getRelZoneDN(zoneName) modAttrs = [(ldap.MOD_REPLACE, 'sOARecord', sOARecord)] DN = self.addDN("relativeDomainName=@", relZoneDN) if not self.modAttrsDN(DN, modAttrs): self.printERROR(_("Can not write new serial number for zone %s \ in LDAP")%zoneName) return False return True def getAllowNet(self): """Получаем от пользователя доверительные сети и устанавливаем переменную профилей sr_dns_net_allow self.clVars должен быть определен """ print _("Enter the allowed ip addresses and network for %s service")\ %"DNS" + " (" + _("comma or space delimited") + ")" strPrompt = _("allow networks: ") netAllow = self.clVars.Get("sr_dns_net_allow") strNetAllow = "" if netAllow: strNetAllow = netAllow.replace(","," ") allowNet = self.getUserAllowNetwork(strPrompt, strNetAllow) if not allowNet: return False # Установка переменной доступные сети allowNet = ",".join(allowNet) self.clVars.Set("sr_dns_net_allow", allowNet ,True) return allowNet def checkSDBLDAP(self): """Проверка ключа sdb-ldap bind""" pathBind = "/var/db/pkg/net-dns" if os.path.exists(pathBind): subPathsBind = filter(lambda x: re.search("bind-\d",x),\ os.listdir(pathBind)) if subPathsBind: pathsUSE = (os.path.join(pathBind,subPathsBind[0],"IUSE"), os.path.join(pathBind,subPathsBind[0],"USE")) if filter(lambda x: not os.path.exists(x), pathsUSE): return False for pathUSE in pathsUSE: flagFound = False try: FD = open(pathUSE) useFlags = FD.read() FD.close() except: break if not "sdb-ldap" in useFlags: break flagFound = True if flagFound: return True return False def setupDnsServer(self, options): """Начальная настройка DNS сервиса""" # Проверка ключа bind sdb-ldap if not self.checkSDBLDAP(): self.printERROR(_('Can not found USE="sdb-ldap" in package bind')) self.printWARNING(_('Key USE="sdb-ldap" added to the package \ net-dns/bind version>=9.6.1')) return False # Принудительная установка forceOptions = False if options.has_key("f"): forceOptions = True # Создаем объект переменных self.createClVars() if self.clVars.Get("sr_ldap_set") != "on": self.printERROR(_("LDAP service is not setuped")) self.printWARNING(_("Setup LDAP service")) self.printWARNING(" cl-setup ldap") return False # В случае если сервер установлен if self.clVars.Get("sr_dns_set") == "on" and\ not forceOptions: self.printWARNING (_("WARNING") + ": " +\ _("DNS server is configured")+ ".") return True # Доверительные сети по умолчанию allowNet = self.clVars.Get("os_net_allow") if not forceOptions: # предупреждение при выполнении этой программы будут изменены # конфигурационные файлы сервиса DNS (программa bind) self.printWARNING (_("WARNING") + ": " + _("Executing of the program will change") + " " + _("the configuration files of DNS service") +" ("+ _("program bind") + ")." ) # если вы готовы продолжить работу программы нажмите Y если нет n messDialog = \ _("If you are ready to continue executing the program") + ", "+\ _("input 'yes'") +", "+ _("if not 'no'") if not self.dialogYesNo(messDialog): return True if options.has_key("a"): # Получаем от пользователя доверительные сети allowNet = self.getAllowNet() if not allowNet: return False else: if options.has_key("a"): # Получаем от пользователя доверительные сети allowNet = self.getAllowNet() if not allowNet: return False # делаем backup # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False bakupObj = servLdap() if not bakupObj.backupServer(): return False # Удаляем переменные сервиса в ini файлах self.deleteServiceVarsInFile("dns") # Cоздаем объект переменные self.createClVars() # Устанавливаем доступные сети self.clVars.Set("sr_dns_net_allow", allowNet, True) # Удаляем из автозапуска демона if not self.delDaemonAutostart("named"): return False # останавливаем сервис DNS if not self.stopServices(["dns"]): return False # Имя устанавливаемого сервиса self.clVars.Set("cl_pass_service","dns") self.clVars.Write("sr_dns_set","off") # Cоздаем объект профиль устанавливая директорию proxy для # файлов профилей if not self.applyProfilesFromService('dns'): return False # Удаляем ненужные текстовые зоны objTxtZone = dnsTxt() printSuccess = lambda x: self.printOK(_('Deleted DNS zone "%s"')%x +\ " " + _("from file %s")%objTxtZone.nameConfigFile) if not objTxtZone.deleteAllZones(printSuccess): return False #delZonesNames = objTxtZone.getAllNamesZones() #relList = map(lambda x: objTxtZone.deleteZone(x), delZonesNames) #flagDelError = False #i = 0 #for ret in relList: #if not ret: #flagDelError = True #break #i += 1 #if flagDelError: #map(lambda x :\ #self.printOK(_('Deleted DNS zone "%s"')%x + " " +\ #_("from file %s")%objTxtZone.nameConfigFile)\ #,delZonesNames) # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False else: if not self.restartLdapServer(): return False # Подключаемся к LDAP cерверу if not shareLdap.getLdapObjInFile(self): return False # Находим в LDAP DNS сервис resSearch = self.searchService() ret = True if resSearch: delDN = self.relDN ret = self.deleteDN(delDN) if ret: self.printOK(_("Remove DNS DN from LDAP Database") + " ...") else: self.printERROR(_("Can not remove DNS DN from LDAP Database")) if not ret: return False ldifFile = self.ldifFileBase baseLdif = self.createLdif(ldifFile) if not self.ldapObj.getError(): self.ldapObj.ldapAdd(baseLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False # Записываем данные администратора сервиса Proxy ldapParser = iniLdapParser() ldapParser.setVar("dns", {"DN":self.clVars.Get("ld_dns_dn"), "PASS":self.clVars.Get("ld_dns_pw")}) self.printOK(_("Added ldif file") + " ...") textLines = self.execProg("/etc/init.d/named start") if textLines == False: self.printNotOK(_("Starting") + " " + "Named" + " ...") return False else: self.printOK(_("Starting") + " " + "Named" + " ...") # Устанавливаем автозапуск демона if not self.setDaemonAutostart("named"): return False # запишем переменные для сервера allow = self.clVars.Get("sr_dns_net_allow") self.clVars.Write("sr_dns_net_allow",allow,True,"local") # запишем переменные для клиента # # Запишем, что сервис установлен self.clVars.Write("sr_dns_set","on") self.printOK(_("DNS service configured") + " ...") return True class servDhcp(shareLdap, shareIP): """Методы сервиса DHCP""" # Путь к resolv.conf resolvFile = "/etc/resolv.conf" hostsFile = "/etc/hosts" # Название файла для вывода ошибок errorLogFile = "dhcp-error.log" def __init__(self): shareLdap.__init__(self) # Объект сервиса DNS self.servDnsObj = servDns() def createHostDhcpServer(self, options, checkSetup=True, createDNS=True): """Создание записи о статическом хосте в DHCP cервисе""" # Проверим установлен ли сервис dhcp if checkSetup and not self.isServiceSetup("dhcp"): return False optKeys = options.keys() minKeys = ["host", "ip", "mac"] # Проверка на наличие всех нужных опций if not set(minKeys)<=set(optKeys): notFoundKeys = list(set(minKeys)-set(optKeys)) notFoundKeys = map(lambda x: len(x)>1 and '"--%s"'%x or '"-%s"'%x,\ notFoundKeys) self.printERROR(_("Not enough command line options: %s")\ %", ".join(notFoundKeys)) return False # имя хоста hostname = options["host"] # Проверка правильности названия хоста if '.' in hostname: self.printERROR(_('Command line option "--host %s" incorrectly')\ %hostname) self.printWARNING(_("Example") + " :") self.printWARNING('"--host computer') return False # ip адрес хоста ip = options["ip"] # проверка правильности ip if "," in ip or not self.isCorrectStringNet(ip, False): self.printERROR(_('Command line option "--ip %s" incorrectly')%ip) self.printERROR(_("IP address %s incorrectly")%ip) return False dhcpObj = dncpTxt() # проверка диапазона для ip if not self.isCorrectStaticIP(ip, dhcpObj): self.printERROR(_("incorrect ip %s")%ip) return False # mac адрес хоста mac = options["mac"] if mac: mac = mac.lower() if not self.isCorrectMacAddress(mac): self.printERROR(_('Command line option "--mac %s" incorrectly')\ %mac) self.printERROR(_("Mac address %s incorrectly")%mac) self.printWARNING(_("Example") + " :") self.printWARNING('"--mac 00:23:32:fa:b7:07') return False # Проверка наличия mac адреса в конфигурационном файле if not self.isNotExistsStaticMAC(mac, dhcpObj): self.printERROR(_("incorrect mac %s")%mac) return False if self.isServiceSetup("dns"): # Находим полное имя хоста fullHostName = self.getFullHostNameInConfig(hostname, ip) if not fullHostName: return False if createDNS: # Создаем DNS Host if not self.createDNSHost(fullHostName, ip, False): return False if not dhcpObj.createStaticHost(hostname, ip, mac): return False if not self.restartDhcp(): return False self.printSUCCESS(_("Created static host %s") %hostname) return True def getDataInConfig(self, netNoMask): """По ip сети получить информацию о DHCP сети""" dhcpObj = dncpTxt() dataNets = dhcpObj.getDataInAllSubnet() if not dataNets: self.printERROR(_("Can not found networks in config file %s")\ %dhcpObj.nameConfigFile) return False flagError = False ranges = [] dnsIPs = [] domainNames = [] for net, data in dataNets: if netNoMask == net: notFoundOpts = [] if data.has_key("range"): ranges = filter(lambda x: x.strip(), data["range"]) if not ranges: notFoundOpts.append(("range", "--range ")) if data.has_key("optiondomain-name-servers"): dnsIPs = data["optiondomain-name-servers"][0].split(",") if not dnsIPs: notFoundOpts.append(("option domain-name-servers", "--dnsip ")) if data.has_key("optiondomain-name"): domainNames = map(lambda x: x.strip().replace('"',''),\ data["optiondomain-name"]) if not domainNames: notFoundOpts.append(("option domain-name", "--dnames ")) if notFoundOpts: optionsPr = map(lambda x: "'%s'"%x[0], notFoundOpts) optionsCmdPr = map(lambda x: x[1], notFoundOpts) self.printERROR(_("Can not create DNS zone %s") %net) self.printERROR(\ _('Can not found %s')%",".join(optionsPr) + " "+\ _('in subnet "%s"')%net + " " + _("in config file %s")\ %dhcpObj.nameConfigFile) self.printERROR(_("Use command:")) self.printERROR("cl-dhcp-netmod %s %s/24"%(\ " ".join(optionsCmdPr),net)) flagError = True break break if flagError: return [] else: return [ranges, dnsIPs, domainNames] def getFullHostNameInConfig(self, hostname, ip, dhcpObj=False): """По имени хоста и ip получаем полное имя хоста из конфигурационного файла dhcpd.conf""" if not dhcpObj: dhcpObj = dncpTxt() dataNets = dhcpObj.getDataInAllSubnet() if not dataNets: self.printERROR(_("Can not found networks in config file %s")\ %dhcpObj.nameConfigFile) return False flagError = False isRange = lambda n, minN, maxN: minN<=n<=maxN domainNames = [] for net, data in dataNets: try: netAndMask = self.getNet(net, data["mask"][0]) except: self.printERROR(_('Incorrect netmask "%s" in')\ %data["mask"][0] +\ " " + _("in config file %s") %dhcpObj.nameConfigFile) flagError = True break minNumber, maxNumber = self.getMinAndMaxIpNumb(netAndMask) ipNumb = self.getNumberIP(ip) domainNames = [] if isRange(ipNumb, minNumber, maxNumber): if data.has_key("optiondomain-name"): domainNames = map(lambda x: x.strip().replace('"',''),\ data["optiondomain-name"]) break else: self.printERROR(\ _('Can not found "option domain-name"')+\ " " +_("in 'subnet %s'")%net + " " +\ _("in config file %s")\ %dhcpObj.nameConfigFile) flagError = True break if flagError: return False if not domainNames: self.printERROR(_('Can not found "option domain-name"')+" "+\ _("in config file %s")\ %dhcpObj.nameConfigFile) return False return "%s.%s" %(hostname,domainNames[0]) def isRangeNet(self, ip, net): """Попадает ли ip в диапазон сети""" minNumber, maxNumber = self.getMinAndMaxIpNumb(net) ipNumb = self.getNumberIP(ip) # Проверка на попадание в диапазон сети isRange = lambda n, minN, maxN: minN<=n<=maxN if isRange(ipNumb, minNumber, maxNumber): return True else: return False def isCorrectNet(self, net): """Проверка корректности сети на основании сетевых интерфейсов""" network, spl, netmask = net.rpartition("/") intNetmask = int(netmask) if intNetmask < 16: self.printERROR(_('Incorrect network %s')%net) self.printWARNING(_("Minimum network mask /16")) return False if not self.clVars: self.createClVars() # Минимальный и максимальный номер ip сети minNumber, maxNumber = self.getMinAndMaxIpNumb(net) osNets = self.clVars.Get("os_net_allow") serverNets = osNets.split(',') dataMinMaxIP = map(lambda x: self.getMinAndMaxIpNumb(x), serverNets) # Проверка на попадание в диапазон сети isRange = lambda n, minN, maxN: minN<=n<=maxN if filter(lambda x: isRange(minNumber,x[0],x[1]) and\ isRange(maxNumber,x[0],x[1]), dataMinMaxIP): return True self.printERROR("Can not found network %s in network interfaces: \ eth0, eth1, ... etc."%net) if osNets: self.printWARNING(_("Existing nets: %s")%osNets) return False def isCorrectMacAddress(self, mac): """Проверка правлиьности mac адреса""" macNumbers = mac.split(':') if not len(macNumbers) == 6: return False flagOK = True for hexNumber in macNumbers: try: exec("0x%s"%hexNumber) except: flagOK = False break return flagOK def modHostDhcpServer(self, options, hostname): """Модификация записи о хосте в DHCP сервисе""" # Проверим установлен ли сервис dhcp if not self.isServiceSetup("dhcp"): return False if not options: self.printERROR(_("Can not found command line options")) return False # Проверка правильности названия хоста if '.' in hostname: self.printERROR(_('Hostname %s incorrectly')%hostname) return False dhcpObj = dncpTxt() xmlNodesNet = dhcpObj.getXMLStaticHost(hostname) if not xmlNodesNet: self.printERROR(_("Can not found static host %s") %hostname + " "+\ _("in config file %s") %dhcpObj.nameConfigFile) return False ip = "" if options.has_key("ip"): # ip адрес хоста ip = options["ip"] # проверка правильности ip if "," in ip or not self.isCorrectStringNet(ip, False): self.printERROR(_('Command line option "--ip %s" incorrectly')\ %ip) self.printERROR(_("IP address %s incorrectly")%ip) return False # проверка диапазона для ip if not self.isCorrectStaticIP(ip, dhcpObj): self.printERROR(_("incorrect ip %s")%ip) return False if self.isServiceSetup("dns"): # Находим полное имя хоста fullHostName = self.getFullHostNameInConfig(hostname, ip) if not fullHostName: return False if not self.modifyDNSHostIP(fullHostName, ip): return False mac = "" if options.has_key("mac"): # mac адрес хоста mac = options["mac"] if mac: mac = mac.lower() if not self.isCorrectMacAddress(mac): self.printERROR(\ _('Command line option "--mac %s" incorrectly') %mac) self.printERROR(_("Mac address %s incorrectly")%mac) self.printWARNING(_("Example") + " :") self.printWARNING('"--mac 00:23:32:fa:b7:07') return False # Проверка наличия mac адреса в конфигурационном файле if not self.isNotExistsStaticMAC(mac, dhcpObj): self.printERROR(_("incorrect mac %s")%mac) return False ret = dhcpObj.modHostOpts(xmlNodesNet[0], ip, mac) if not self.restartDhcp(): return False if ret: self.printSUCCESS(_("Modify static host %s") %hostname) if ip: self.printSUCCESS(_("ip -> %s")%ip) if mac: self.printSUCCESS(_('mac address -> %s')%mac) return ret def modNetDhcpServer(self, options, net): """Модификация записи о сети в DHCP сервисе""" # Проверим установлен ли сервис dhcp if not self.isServiceSetup("dhcp"): return False if not options: self.printERROR(_("Can not found command line options")) return False # проверка правильности сети network, spl, netmask = net.rpartition("/") if not self.isCorrectStringNet(net): self.printERROR(_('Incorrect network %s')%net) self.printWARNING(_("Example network") + " :") self.printWARNING('"192.168.0.0/24"') return False # Проверка сущестовования сети в конфигурационном файле if not self.isExistingNet(net): return False dhcpObj = dncpTxt() xmlNodesNet = dhcpObj.getXMLNet(network) # ip роутера router = "" if options.has_key("router"): router = options["router"] # Проверка коректности ip роутера if "," in router or not self.isCorrectStringNet(router, False): self.printERROR(\ _('Command line option "--router %s" incorrectly')\ %router) self.printERROR(_("IP address %s incorrectly")%router) return False domainNames = [] if options.has_key("dnames"): # доменные имена для поиска domainNames = map(lambda x: x.lower(), options["dnames"].split(",")) domainNames = self.unicList(domainNames) # проверка доменных имен на ip incorrectDomains = filter(lambda x:\ self.isCorrectStringNet(x, False), domainNames) if incorrectDomains: self.printERROR(_('Incorrect command line option "--dnames"')) self.printWARNING(_("Example") + ":") self.printWARNING("--dnames domain.ru,domain.com") return False dhcpObj = dncpTxt() ranges = [] if options.has_key("range"): # Диапазон динамических ip ranges = self.isCorrectIPRangeListAndSort(net, options["range"].split(",")) if not ranges: self.printERROR(_('Incorrect command line option "--range"')) self.printWARNING(_("Example") + ":") self.printWARNING("--range 192.168.0.50,192.168.0.254") return False # Проверка на статические ip if not self.isCorrectNetRange(net, ranges, dhcpObj): self.printERROR(_("range %s incorrectly")%",".join(ranges)) return False # Удаляем динамические ip if not self.removeDynamicDNSRecords(net): return False dnsIP = "" # ip адреса dns серверов if options.has_key("dnsip"): dnsIP = options["dnsip"] # проверка правильности ip if not self.isCorrectStringNet(dnsIP, False) or\ len(dnsIP.split(',')) > 3: self.printERROR(\ _('Command line option "--dnsip %s" incorrectly')%dnsIP) self.printERROR(_("IP addresses %s incorrectly")%dnsIP) return False domainsTxt = " ".join(domainNames) rangesTxt = " ".join(ranges) if self.isServiceSetup("dns"): # Создание DNS зоны и перенос DNS хостов из DHCP в новую зону DNS if domainNames: # Хосты для переноса moveRecords = self.getDNSRecords(net) if moveRecords == False: return False # Данные для зоны из dhcpd.conf dataConfig = self.getDataInConfig(network) if not dataConfig: return False oldRanges, oldDnsIPs, oldDomainNames = dataConfig # Модификация resolv.conf flagModifyResolv = False if oldDomainNames == self.getSearchDomainsInResolvFile(): flagModifyResolv = True hostname = self.servDnsObj.clVars.Get("os_net_hostname") if hostname: zone = oldDomainNames[0] fullServerDNSName = "%s.%s"%(hostname,zone) if not filter(lambda x: fullServerDNSName==x[0],\ moveRecords): foundServ = self.servDnsObj.searchDomainNameInLDAP(\ fullServerDNSName) if foundServ: serverIP = foundServ[0][0][1]['aRecord'][0] moveRecords.append((fullServerDNSName,serverIP)) data = [oldDnsIPs, oldRanges, net] if not self.modifyDNSZoneName(oldDomainNames[0], domainNames[0], moveRecords, data): return False # Модификация resolv.conf if flagModifyResolv: # Модифицируем resolv.conf self.createResolvFile(options["dnames"]) if hostname: # Модификация hosts self.createHostsFile("%s.%s"%(hostname,domainNames[0])) ret = dhcpObj.modNetOpts(xmlNodesNet[0], router, domainsTxt, dnsIP, rangesTxt) if not self.restartDhcp(): return False if ret: self.printSUCCESS(_("Modify network %s")%net) if router: self.printSUCCESS(_("router -> %s")%router) if domainNames: self.printSUCCESS(_('domain names -> "%s"')%domainsTxt) if dnsIP: self.printSUCCESS(_('ip domain names servers -> %s')\ %dnsIP) if ranges: self.printSUCCESS(_("range -> %s")%rangesTxt) return ret def delHostDhcpServer(self, options): """Удаление записи о хосте в DHCP сервисе""" # Проверим установлен ли сервис dhcp if not self.isServiceSetup("dhcp"): return False optKeys = options.keys() minKeys = ["host"] # Проверка на наличие всех нужных опций if not set(minKeys)<=set(optKeys): notFoundKeys = list(set(minKeys)-set(optKeys)) notFoundKeys = map(lambda x: len(x)>1 and '"--%s"'%x or '"-%s"'%x,\ notFoundKeys) self.printERROR(_("Not enough command line options: %s")\ %", ".join(notFoundKeys)) return False # имя хоста hostname = options["host"] # Проверка правильности названия хоста if '.' in hostname: self.printERROR(_('Command line option "--host %s" incorrectly')\ %hostname) self.printWARNING(_("Example") + " :") self.printWARNING('"--host computer') return False dhcpObj = dncpTxt() ip = "" if self.isServiceSetup("dns"): # Находим ip хоста dataHosts = dhcpObj.getDataInAllHost() for host, data in dataHosts: if hostname == host and data.has_key("fixed-address"): if data["fixed-address"]: ip = data["fixed-address"][0] break if not dhcpObj.deleteStaticHost(hostname): self.printERROR(_("Can not delete DHCP static host %s")%hostname) return False if self.isServiceSetup("dns") and ip: # Находим полное имя хоста fullHostName = self.getFullHostNameInConfig(hostname, ip, dhcpObj) if not fullHostName: return False # Удаляем хост из DNS if not self.deleteDNSHost(fullHostName): return False if not self.restartDhcp(): return False self.printSUCCESS(_("Deleted DHCP static host %s")%hostname) return True def isExistingNet(self, net): """Проверяет существование сети в конфигурационном файле""" dhcpObj = dncpTxt() dataNets = dhcpObj.getDataInAllSubnet() if not dataNets: self.printERROR(_("Can not found networks in config file %s")\ %dhcpObj.nameConfigFile) return False getPar = lambda opt, data: map(lambda x: opt in x[1].keys() and\ (x[0],x[1][opt]) or (), data) nets = getPar('mask', dataNets) if not nets: self.printERROR(\ _("Can not found 'subnet' and 'netmask' in config file %s")\ %dhcpObj.nameConfigFile) return False minIpDel,maxIpDel = self.getMinAndMaxIpNumb(net) flagFoundNet = False confNets = [] for netData in nets: ipNet, ipMask = netData confNets.append(self.getNet(ipNet, ipMask[0])) minIp,maxIp = self.getMinAndMaxIpNumb(ipNet, ipMask[0]) if minIp==minIpDel and maxIp==maxIpDel: flagFoundNet = True break if not flagFoundNet: self.printERROR(_("Can not found net %s")%net + " "+\ _("in config file %s") %dhcpObj.nameConfigFile) if confNets: self.printWARNING(_("Existing nets: %s")%",".join(confNets)) return False return True def delNetDhcpServer(self, options): """Удаление записи о сети в DHCP сервисе""" # Проверим установлен ли сервис dhcp if not self.isServiceSetup("dhcp"): return False optKeys = options.keys() minKeys = ["net"] # Проверка на наличие всех нужных опций if not set(minKeys)<=set(optKeys): notFoundKeys = list(set(minKeys)-set(optKeys)) notFoundKeys = map(lambda x: len(x)>1 and '"--%s"'%x or '"-%s"'%x,\ notFoundKeys) self.printERROR(_("Not enough command line options: %s")\ %", ".join(notFoundKeys)) return False # ip сети и сетевая маска /24 net = options["net"] # проверка правильности сети network, spl, netmask = net.rpartition("/") if not self.isCorrectStringNet(net): self.printERROR(_('Incorrect network %s')%net) self.printWARNING(_("Example network") + " :") self.printWARNING('"--net 192.168.0.0/24"') return False # Проверка сущестовования сети в конфигурационном файле if not self.isExistingNet(net): return False netIP = net.partition("/")[0] dhcpObj = dncpTxt() if not dhcpObj.deleteNet(netIP): self.printERROR(_("Can not delete DHCP network %s")%net) return False # Если нет сетей останавливаем DHCP сервер if not dhcpObj.getAllXMLSubnet(): self.printWARNING(_("Can not found networks ('subnet')") + " "+\ _("in config file %s")\ %dhcpObj.nameConfigFile) if not self.stopDhcp(): return False self.printOK(_("Stopping") + " " + "dhcpd" + " ...") else: if not self.restartDhcp(): return False self.printSUCCESS(_("Deleted DHCP network %s")%net) return True def getSearchDomainsInResolvFile(self): """Получить список search доменов из /etc/resolv.conf""" searchDomains = [] if not os.path.exists(self.resolvFile): return searchDomains FD = open(self.resolvFile) lines = FD.readlines() FD.close() linesSearchDomains = filter(lambda x: "search " in x or\ "search\t" in x, lines) if linesSearchDomains: searchDomains = filter(lambda x: x,\ linesSearchDomains[0].partition("search")[2].replace("\t",\ " ").split(" ")) return map(lambda x: x.rstrip(), searchDomains) def createResolvFile(self, searchDomains): """Создание и модификация /etc/resolv.conf""" dnsIP = "127.0.0.1" mode = 0644 domainNames = map(lambda x: x.lower(), searchDomains.split(",")) domainNames = self.unicList(domainNames) searchDomains = " ".join(domainNames) if not os.path.exists(self.resolvFile): fd = os.open(self.resolvFile, os.O_CREAT) os.close(fd) fileObj = cl_profile._file() dMode, dUid, dGid = fileObj.getModeFile(self.resolvFile) if dMode != mode: os.chmod(self.resolvFile, mode) if dUid!=0 or dUid!=0: os.chown(self.resolvFile,0,0) resolvFileText = "search %s\nnameserver %s"%(searchDomains,dnsIP) FD = open(self.resolvFile, "r+") FD.truncate(0) FD.seek(0) FD.write(resolvFileText) FD.close() return True def createHostsFile(self, fullHostName): """Создание и модификация /etc/hosts""" dnsIP = "127.0.0.1" mode = 0644 hostname, spl, domainName = fullHostName.partition(".") if not domainName: domainName = "local" if not os.path.exists(self.hostsFile): fd = os.open(self.hostsFile, os.O_CREAT) os.close(fd) fileObj = cl_profile._file() dMode, dUid, dGid = fileObj.getModeFile(self.hostsFile) if dMode != mode: os.chmod(self.resolvFile, mode) if dUid!=0 or dUid!=0: os.chown(self.hostsFile,0,0) hostsFileText = "%s %s.%s %s localhost"\ %(dnsIP, hostname, domainName, hostname) FD = open(self.hostsFile, "r+") lines = FD.readlines() if not lines: lines = [hostsFileText+"\n"] newLines = [] for line in lines: if dnsIP in line: newLines.append(hostsFileText+"\n") else: newLines.append(line) FD.truncate(0) FD.seek(0) FD.write("".join(newLines)) FD.close() return True def createNetDhcpServer(self, options, checkSetup=True): """Создание записи о сети в DHCP cервисе""" # Проверим установлен ли сервис dhcp if checkSetup and not self.isServiceSetup("dhcp"): return False optKeys = options.keys() minKeys = ["net", "router", "range", "dnames", "dnsip"] # Проверка на наличие всех нужных опций if not set(minKeys)<=set(optKeys): notFoundKeys = list(set(minKeys)-set(optKeys)) notFoundKeys = map(lambda x: len(x)>1 and '"--%s"'%x or '"-%s"'%x,\ notFoundKeys) self.printERROR(_("Not enough command line options: %s")\ %", ".join(notFoundKeys)) return False # ip сети и сетевая маска /24 net = options["net"] if not self.isCorrectStringNet(net): self.printERROR(_('Incorrect network %s')%net) self.printWARNING(_("Example network") + " :") self.printWARNING('"--net 192.168.0.0/24"') return False # проверка наличия сети на интерфейсах сервера if not self.isCorrectNet(net): return False # ip роутера router = options["router"] # Проверка коректности ip роутера if "," in router or not self.isCorrectStringNet(router, False): self.printERROR(_('Command line option "--router %s" incorrectly')\ %router) self.printERROR(_("IP address %s incorrectly")%router) return False # доменные имена для поиска domainNames = [] if options.has_key("dnames"): domainNames = map(lambda x: x.lower(), options["dnames"].split(",")) domainNames = self.unicList(domainNames) # проверка доменных имен на ip incorrectDomains = filter(lambda x:\ self.isCorrectStringNet(x, False), domainNames) if incorrectDomains: self.printERROR(_('Incorrect command line option "--dnames"')) self.printWARNING(_("Example") + ":") self.printWARNING("--dnames domain.ru,domain.com") return False # Диапазон динамических ip ranges = self.isCorrectIPRangeListAndSort(net, options["range"].split(",")) if not ranges: self.printERROR(_('Incorrect command line option "--range"')) self.printWARNING(_("Example") + ":") self.printWARNING("--range 192.168.0.50,192.168.0.254") return False dnsIP = "" # ip адреса dns серверов if options.has_key("dnsip"): dnsIP = options["dnsip"] # проверка правильности ip if not self.isCorrectStringNet(dnsIP, False) or\ len(dnsIP.split(',')) > 3: self.printERROR(\ _('Command line option "--dnsip %s" incorrectly')%dnsIP) self.printERROR(_("IP addresses %s incorrectly")%dnsIP) return False dhcpObj = dncpTxt() # Проверка на статические ip ranges if not self.isCorrectNetRange(net, ranges, dhcpObj): self.printERROR(_("range %s incorrectly")%",".join(ranges)) return False if not dhcpObj.createNet(net, router, domainNames, dnsIP, ranges): return False # Флаг создания DNS зоны flagCreateDNSZone = False # Добавление зоны в DNS if self.isServiceSetup("dns"): dnsIPs = dnsIP.split(",") # Создание зоны domainNames[0] if not self.createDNSZone(domainNames, dnsIPs, ranges, net): return False if not self.restartDhcp(): return False self.printSUCCESS(_("Created net %s") %net) return True def deleteDNSHost(self, fullHostName): """Удаляет A и PTR записи из DNS сервиса""" recData = self.servDnsObj.searchAllDomainNamesInLDAP(fullHostName) ip = "" if recData: if recData[0][0][1].has_key('aRecord'): ip = recData[0][0][1]['aRecord'][0] # Удаляем A запись if not self.servDnsObj.delRecordDnsServer({"host":fullHostName}, False): return False # Удаляем PTR запись if ip: # Ищем PTR запись в DNS dataIP = self.servDnsObj.getDomainAndZoneFromIP(ip) hostNameTmp, PTRDomainName, zoneNameTmp = dataIP # Находим ptr запись в DNS recData = self.servDnsObj.searchAllDomainNamesInLDAP(\ PTRDomainName) # Находит ip на основании имени хоста в обратной зоне # Удаляемые ip в обратной зоне deleteIP = self.servDnsObj.searchIPForHostInReverse(\ fullHostName) if recData: if recData[0][0][1].has_key('pTRRecord'): hostList = recData[0][0][1]['pTRRecord'] # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x,\ y.split("."))) hostList = map(lambda x: delDot(x),hostList) if not fullHostName in hostList: deleteIP.append(ip) deleteIP = list(set(deleteIP)) # Удаляем PTR записи в обратной зоне for delIP in deleteIP: if not self.servDnsObj.delRecordDnsServer(\ {"ip":delIP},False): return False return True def createDNSHost(self, fullHostName,ip,delDNSRecord=True,checkName=True): """Добавляет A и PTR записи в DNS сервис Если запись существует - удаляет ее (delDNSRecord=True) Если запись существует и не в динамическом диапазоне - не делает никаких действий (checkName=True совместно с delDNSRecord=True) """ # Ищем А запись в DNS flagCreateARecord = True flagDelARecord = False recData = self.servDnsObj.searchAllDomainNamesInLDAP(fullHostName) if recData and not delDNSRecord: self.printERROR(_("Record %s exist in service DNS")%fullHostName) return False if recData: flagDelARecord = True if recData[0][0][1].has_key('aRecord'): aRecords = recData[0][0][1]['aRecord'] if ip in aRecords: flagCreateARecord = False flagDelARecord = False if delDNSRecord and checkName: flagFoundIpNotRanges = False dhcpObj = dncpTxt() for ipAdr in aRecords: # Проверка на диапазон адресов flagCorrect, flagError =\ self.isCorrectDynamicIP(\ fullHostName.partition(".")[0], ipAdr, dhcpObj, False) if flagError: return False if not flagCorrect: return True else: # Если тип записи не А то ошибка self.printERROR(_("Record %s exist in service DNS")%\ fullHostName) self.printERROR(_("This record type in DNS is not A-record")) return False else: if delDNSRecord: # Удаляем A записи имеющие этот IP в прямой зоне # Хосты имеющие этот IP в прямой зоне hostsWithIP = self.servDnsObj.searchHostsForIPinForward(ip) if hostsWithIP: flagError = False # Удаляем все хосты имеющие этот ip for delHost in hostsWithIP: if not self.servDnsObj.delRecordDnsServer( {"host":delHost}, False): flagError = True break if flagError: return False # Удаляем А записьи в DNS if delDNSRecord: if flagDelARecord: if not self.servDnsObj.delRecordDnsServer( {"host":fullHostName}, False): return False # Хосты имеющие этот IP в прямой зоне hostsWithIP = self.servDnsObj.searchHostsForIPinForward(ip) if hostsWithIP: flagError = False # Удаляем все хосты имеющие этот ip for delHost in hostsWithIP: if not self.servDnsObj.delRecordDnsServer(\ {"host":delHost}, False): flagError = True break if flagError: return False # Ищем PTR запись в DNS dataIP = self.servDnsObj.getDomainAndZoneFromIP(ip) hostNameTmp, PTRDomainName, zoneNameTmp = dataIP # Находим ptr запись в DNS recData = self.servDnsObj.searchAllDomainNamesInLDAP(\ PTRDomainName) if recData and not delDNSRecord: self.printERROR(_("%s exist in service DNS")\ %ip) self.printERROR(_("PTR-record %s exist in service DNS")\ %PTRDomainName) return False # Находит ip на основании имени хоста в обратной зоне # Удаляемые ip в обратной зоне deleteIP = self.servDnsObj.searchIPForHostInReverse(\ fullHostName) # Флаг создания обратной записи flagCreatePTRRecord = True if recData: if recData[0][0][1].has_key('pTRRecord'): hostList = recData[0][0][1]['pTRRecord'] # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x,\ y.split("."))) hostList = map(lambda x: delDot(x),hostList) if fullHostName in hostList: deleteIP = filter(lambda x: x!=ip, deleteIP) flagCreatePTRRecord = False else: deleteIP.append(ip) deleteIP = list(set(deleteIP)) # Удаляем PTR записи в обратной зоне for delIP in deleteIP: if not self.servDnsObj.delRecordDnsServer(\ {"ip":delIP},False): return False # Добавляем A и PTR записи в DNS if flagCreateARecord: optionsDns = {"t":"a", "host":fullHostName, "ip":ip} if not self.servDnsObj.addRecordDnsServer(optionsDns): return False return True def addDNSHost(self, fullHostName, ip, adminDn, adminPw, baseDN): """Добавляет DNS хост""" # Создаем объект переменных если необходимо if not self.servDnsObj.clVars: self.servDnsObj.createClVars() # Записываем в переменную базовый DN self.servDnsObj.clVars.Set("ld_base_dn", baseDN, True) # Подключаемся к LDAP if not self.servDnsObj.connectToLDAP(adminDn, adminPw): return False # Ищем сервис DNS в LDAP if not self.servDnsObj.searchService(): return False # Создаем DNS host if not self.createDNSHost(fullHostName, ip): return False return True def addDNSRecordServer(self, options, logObj=False): """Добавляет подключившийся к DHCP компьютер в DNS сервис""" # Если есть объект логгирования if logObj: # Переопределяем методы печати ошибок printERROR = lambda x:\ cl_utils2.cl_smartcon.printERROR(self, x) or\ logObj.writeError(x) self.printERROR = printERROR self.servDnsObj.printERROR = printERROR optKeys = options.keys() minKeys = ["ip", "domain", "host", "s", "b"] # Проверка на наличие всех нужных опций if not set(minKeys)<=set(optKeys): notFoundKeys = list(set(minKeys)-set(optKeys)) notFoundKeys = map(lambda x: len(x)>1 and '"--%s"'%x or '"-%s"'%x,\ notFoundKeys) self.printERROR(_("Not enough command line options: %s")\ %", ".join(notFoundKeys)) return False optPwd = ["p","P"] listOptPwd = filter(lambda x: x in optPwd, options.keys()) if len(listOptPwd) > 1: self.printERROR(_("Command line options '-p' and '-P' are \ incompatible, use one of the options")) return False adminDn = options['s'] if options.has_key("p"): adminPw = options['p'] elif options.has_key("P"): pathPasswd = options['P'] if os.path.exists(pathPasswd): try: FD = open(pathPasswd, "r") adminPw = FD.read().strip() FD.close() except: self.printERROR(_("Can not read file %s") %pathPasswd) return False else: self.printERROR(_("Can not find file %s") %pathPasswd) return False if not adminPw: self.printERROR(_("Empty file %s") %pathPasswd) return False baseDN = options['b'] ip = options['ip'] if "," in ip or not self.isCorrectStringNet(ip, False): self.printERROR(_("IP address %s incorrectly")%ip) return False domain = options['domain'] listDomain = filter(lambda x: x.strip(), domain.split(" ")) if not listDomain: self.printERROR(_('Incorrect command line option "--domain"')) return False domain = listDomain[0].strip() host = options['host'] fullHostName = "%s.%s"%(host,domain) # Проверка на диапазон адресов flagCorrect, flagError = self.isCorrectDynamicIP(host, ip) if flagError: return False if not flagCorrect: return True # устанавливаем переменные в объекте сервиса DHCP self.createClVars() self.clVars.Set("sr_dhcp_set","on",True) self.clVars.Set("sr_dns_set","on",True) self.servDnsObj.clVars = self.clVars if not self.addDNSHost(fullHostName, ip, adminDn, adminPw, baseDN): return False return True def getDNSRecords(self, netAndMask): """Находит A записи в DNS которые удовлетворяют параметрам DHCP сети""" network, spl, netmask = netAndMask.rpartition("/") dataConfig = self.getDataInConfig(network) if not dataConfig: return False oldRanges, oldDnsIPs, oldDomainNames = dataConfig dhcpObj = dncpTxt() try: minIpRange, maxIpRange = sorted([self.getNumberIP(oldRanges[0]), self.getNumberIP(oldRanges[1])]) except: self.printErrConfig(dhcpObj, network) return False # Поиск статических хостов в конфигурационном файле dhcpd.conf dataHosts = dhcpObj.getDataInAllHost() flagError = False minIp, maxIp = self.getMinAndMaxIpNumb(netAndMask) # Проверка на попадание в диапазон сети isRange = lambda n, minN, maxN: minN<=n<=maxN zone = oldDomainNames[0] retData = {} # Поиск статических DHCP хостов в DNS for hostname, data in dataHosts: ip = "" if not data.has_key("fixed-address"): self.printERROR(_("Can not found ip static host %s")\ %hostname+ " " + _("in config file %s")\ %dhcpObj.nameConfigFile) flagError = True break if not data["fixed-address"]: self.printERROR(_("Can not found ip static host %s")\ %hostname+ " " + _("in config file %s")\ %dhcpObj.nameConfigFile) flagError = True break ip = data["fixed-address"][0] # Полное имя хоста fullDomainName = "" # Если статический хост в диапазоне сети if isRange(self.getNumberIP(ip), minIp, maxIp): fullDomainName = "%s.%s"%(hostname,zone) recData = self.servDnsObj.searchAllDomainNamesInLDAP(\ fullDomainName) if recData: if recData[0][0][1].has_key('aRecord'): aRecords = recData[0][0][1]['aRecord'] if ip in aRecords: retData[fullDomainName] = ip else: self.printERROR(_("DHCP static host %s")%hostname) self.printERROR(_("DHCP ip %s")%ip) self.printERROR(_("DNS host %s")%fullDomainName) self.printERROR(_("DNS ip %s")%",".join(aRecords)) self.printERROR(_("IP addresses do not match")) flagError = True break else: self.printERROR(\ _("Can not found A-record %s in DNS service")\ %fullDomainName) flagError = True break else: self.printERROR(\ _("Can not found A-record %s in DNS service")\ %fullDomainName) flagError = True break if not flagError: # Поиск динамических DHCP хостов в DNS zoneName = oldDomainNames[0] # Поиск подходящих хостов в DNS dynamicHosts = self.foundDynamicDNSRecords(zoneName, minIpRange, maxIpRange) retData.update(dynamicHosts) if flagError: return False return retData.items() def foundDynamicDNSRecords(self, zoneName, minIpRange, maxIpRange): """Находит имена динамических хостов minIpRange, maxIpRange - максимальный и минимальный номер ip """ retData = {} isRange = lambda n, minN, maxN: minN<=n<=maxN recordsSearch = self.servDnsObj.searchAllRecordInZone(zoneName) if recordsSearch: for record in recordsSearch: domainName = "%s.%s"\ %(record[0][1]["relativeDomainName"][0],\ zoneName) if record[0][1].has_key("aRecord"): ip = record[0][1]["aRecord"][0] # ip в диапазоне динамических адресов if isRange(self.getNumberIP(ip), minIpRange, maxIpRange): retData[domainName] = ip return retData.items() def removeDynamicDNSRecords(self, netAndMask): """Удаляет динамические адреса для сети""" network, spl, netmask = netAndMask.rpartition("/") dataConfig = self.getDataInConfig(network) if not dataConfig: return False oldRanges, oldDnsIPs, oldDomainNames = dataConfig dhcpObj = dncpTxt() try: minIpRange, maxIpRange = sorted([self.getNumberIP(oldRanges[0]), self.getNumberIP(oldRanges[1])]) except: self.printErrConfig(dhcpObj, network) return False # Поиск динамических DHCP хостов в DNS zoneName = oldDomainNames[0] # Поиск подходящих хостов в DNS dynamicHosts = self.foundDynamicDNSRecords(zoneName, minIpRange, maxIpRange) flagError = False for fullHostName, tmpIP in dynamicHosts: if not self.deleteDNSHost(fullHostName): flagError = True break if flagError: return False else: return True def moveDNSRecords(self, newZoneName, moveRecords): """Перенос записей в новую зону""" # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) flagError = False for hostname, ip in moveRecords: newHostName = ".".join([hostname.partition(".")[0],newZoneName]) if newHostName == hostname: continue foundMain = self.servDnsObj.searchDomainNameInLDAP(hostname) if not foundMain: continue otherIP = foundMain[0][0][1]['aRecord'][0] # Поиcк в обратной зоне dataIP = self.servDnsObj.getDomainAndZoneFromIP(otherIP) otherHostName, otherDomain, otherZoneName = dataIP flagMovePTR = True foundOther = self.servDnsObj.searchAllDomainNamesInLDAP(otherDomain) if not foundOther: flagMovePTR = False #else: ## Проверка на соответствие имени хоста #if hostname!=delDot(foundOther[0][0][1]['pTRRecord'][0]): #self.printERROR(_("Found PTR-record %s in LDAP")\ #%otherDomain) #self.printERROR("%s --> %s"%(otherIP,\ #delDot(foundOther[0][0][1]['pTRRecord'][0]))) #self.printERROR("") #flagError = True #break # Поиск в новой зоне A записи foundNewARec = self.servDnsObj.searchDomainNameInLDAP(newHostName) if foundNewARec: if foundNewARec[0][0][1].has_key('aRecord'): if foundNewARec[0][0][1]['aRecord'][0] != otherIP: self.printERROR(_("Record %s exists in DNS service")\ %newHostName) self.printERROR("%s --> %s"%(newHostName,\ foundNewARec[0][0][1]['aRecord'][0])) self.printERROR("") flagError = True break else: self.printERROR(_("Record %s exists in DNS service")\ %newHostName) flagError = True break if foundNewARec: # Удаление старой A записи if not self.servDnsObj.delRecordDnsServer({'host':hostname},\ False): flagError = True break else: # Изменение доменного имени A записи (прямая зона) if not self.servDnsObj.moveARecord(otherIP, hostname, newHostName): flagError = True break if flagMovePTR: # Изменение доменного имени PTR записи (обратная зона) if not self.servDnsObj.modPTRRecord(otherIP, otherHostName, otherDomain, otherZoneName, newHostName): flagError = True break else: # Создание PTR записи optionsDns = {"t":"ptr", "ip":otherIP, "host":newHostName} if not self.servDnsObj.addRecordDnsServer(optionsDns): flagError = True break if flagError: return False return True def modifyDNSZoneName(self, zoneName, newZoneName, moveRecords, data): """Создает новую зону в DNS, переносит туда DHCP записи """ dnsIPs, ranges, net = data # Создание новой зоны если ее нет if not self.createDNSZone([newZoneName], dnsIPs, ranges, net): return False # Перенос записей в новую зону if not self.moveDNSRecords(newZoneName, moveRecords): return False return True def modifyDNSHostIP(self, fullHostName, newip): """Изменяет ip A и PTR записи в DNS сервисе """ # Ищем А запись в DNS flagCreateARecord = True flagDelARecord = False recData = self.servDnsObj.searchAllDomainNamesInLDAP(fullHostName) if recData: if not self.servDnsObj.modRecordDnsServer({"ip":newip}, fullHostName): return False return True def createDNSZone(self, domainNames, dnsIPs, ranges, net): """Создание DNS зоны domainNames[0] domainNames - список доменных имен dnsIPs - список ip DNS серверов net - ip сети c маской (например 10.0.0.0\24) """ # Ищем прямую зону в DNS zoneName = domainNames[0] dnsIP = ",".join(dnsIPs) if not self.servDnsObj.searchZoneInLDAP(zoneName): # Находим все ip DNS cервера IPs = filter(None, self.servDnsObj.clVars.Get("os_net_ip").split(",")) if not IPs: self.printERROR(_("Can not found ip in net interfaces")) return False flagErrorRange = False isRange = lambda n, minN, maxN: minN<=n<=maxN minNumber, maxNumber = self.getMinAndMaxIpNumb(net) for ipRange in ranges: ipNumb = self.getNumberIP(ipRange) if not isRange(ipNumb, minNumber, maxNumber): flagErrorRange = True break if flagErrorRange: self.printERROR(\ _('Command line option "--range %s" incorrectly')\ %",".join(ranges)) self.printERROR( _("Invalid range of network addresses for the network %s")\ %net) return False flagFoundDnsIp = False for ipDns in dnsIPs: ipNumb = self.getNumberIP(ipDns) if isRange(ipNumb, minNumber, maxNumber): flagFoundDnsIp = True break if not flagFoundDnsIp: self.printERROR(\ _('Command line option "--dnsip %s" incorrectly')\ %dnsIP) self.printERROR(_("Can not found ip address dns servers in \ network %s")%net) return False ipserver = "" for ipIntr in IPs: ipNumb = self.getNumberIP(ipIntr) if isRange(ipNumb, minNumber, maxNumber): ipserver = ipIntr break if not ipserver: self.printERROR(\ _("Ip addresses on the interfaces of the system (%s)")\ %",".join(IPs)+" "+_("does not belong to the network %s")\ %net) return False # опции добавления DNS зоны optionsDns = {"n":zoneName, "t":"master", "server":zoneName, "ipserver":ipserver} if not self.servDnsObj.addZoneDnsServer(optionsDns): return False # Ищем обратные зоны в DNS listNet24 = self.nets24ToIpAndMask(net) listStrNet24 = map(lambda x: ".".join(map(lambda y: str(y), x)), listNet24) # Получаем имена обратных зон reverseZoneNames = [] for net24 in listStrNet24: netSpl = net24.split(".") netSpl.pop() netSpl.reverse() # Имя обратной зоны reverseZoneNames.append("%s.in-addr.arpa" %".".join(netSpl)) # Создаем обратные зоны в тексте конфигурационного файла objTxtZone = dnsTxt() if not objTxtZone.createExclZones(self.servDnsObj.clVars, reverseZoneNames, "master"): self.printERROR(\ _("Can not create reverse zones for network %s")%net + " "+\ _("in file %s")%objTxtZone.nameConfigFile) return False # Создаем обратные зоны в LDAP for reverseZoneName in reverseZoneNames: # Создание обратной зоны if not self.servDnsObj.searchZoneInLDAP(reverseZoneName): if not self.servDnsObj.createZoneInLDAP(reverseZoneName, nameServer=zoneName, emailAddr="root@%s"%zoneName, serialNumber="1", refresh=self.servDnsObj.zoneRefresh, updateRetry=self.servDnsObj.zoneUpdateRetry, expiry=self.servDnsObj.zoneExpiry, minimum=self.servDnsObj.zoneMinimum, namesServers=[zoneName], ip="", mxList=[]): return False self.printOK(_("Appended DNS master zone %s")%reverseZoneName) if not self.stopServices(['dns']): return False if not self.startServices(['dns']): return False return True def upgrageDNSZones(self): """Cоздает DNS зоны и статические хосты на основании конфигурационного файла DHCP""" if not self.isServiceSetup("dns"): return True dhcpObj = dncpTxt() dataNets = dhcpObj.getDataInAllSubnet() flagError = False # все сети allNets = [] for net, data in dataNets: notFoundOpts = [] ranges = [] if data.has_key("range"): ranges = filter(lambda x: x.strip(), data["range"]) if not ranges: notFoundOpts.append(("range", "--range ")) try: netAndMask = self.getNet(net, data["mask"][0]) except: self.printERROR(_('Incorrect netmask "%s" in')\ %data["mask"][0] +\ " " + _("in config file %s") %dhcpObj.nameConfigFile) return False dnsIPs = [] if data.has_key("optiondomain-name-servers"): dnsIPs = data["optiondomain-name-servers"][0].split(",") if not dnsIPs: notFoundOpts.append(("option domain-name-servers", "--dnsip ")) domainNames = [] if data.has_key("optiondomain-name"): domainNames = map(lambda x: x.strip().replace('"',''),\ data["optiondomain-name"]) if not domainNames: notFoundOpts.append(("option domain-name", "--dnames ")) if notFoundOpts: optionsPr = map(lambda x: "'%s'"%x[0], notFoundOpts) optionsCmdPr = map(lambda x: x[1], notFoundOpts) self.printERROR(_("Can not create DNS zone %s") %net) self.printERROR(\ _('Can not found %s')%",".join(optionsPr) + " "+\ _('in subnet "%s"')%net + " " + _("in config file %s") %dhcpObj.nameConfigFile) self.printERROR(_("Use command:")) self.printERROR("cl-dhcp-netmod %s %s/24"%(\ " ".join(optionsCmdPr),net)) flagError = True break else: # Создание DNS зоны if not self.createDNSZone(domainNames, dnsIPs, ranges, netAndMask): flagError = True break allNets.append((netAndMask, domainNames[0])) if not flagError: # Поиск статических хостов в конфигурационном файле dhcpd.conf dataHosts = dhcpObj.getDataInAllHost() for hostname, data in dataHosts: ip = "" if not data.has_key("fixed-address"): self.printERROR(_("Can not create static host")) self.printERROR(_("Can not found ip static host %s")\ %hostname+ " " + _("in config file %s")\ %dhcpObj.nameConfigFile) flagError = True break if not data["fixed-address"]: self.printERROR(_("Can not create static host")) self.printERROR(_("Can not found ip static host %s")\ %hostname+ " " + _("in config file %s")\ %dhcpObj.nameConfigFile) flagError = True break ip = data["fixed-address"][0] # Полное имя хоста fullDomainName = "" isRange = lambda n, minN, maxN: minN<=n<=maxN for netAndMask, zone in allNets: minNumber, maxNumber = self.getMinAndMaxIpNumb(netAndMask) ipNumb = self.getNumberIP(ip) if isRange(ipNumb, minNumber, maxNumber): fullDomainName = "%s.%s"%(hostname,zone) if ip and fullDomainName: recData = self.servDnsObj.searchAllDomainNamesInLDAP(\ fullDomainName) if recData: if recData[0][0][1].has_key('aRecord'): aRecords = recData[0][0][1]['aRecord'] if not ip in aRecords: flagError = True else: flagError = True else: # Создание A записи optionsDns = {"t":"a", "autoptr":"off", "host":fullDomainName, "ip":ip} if not self.servDnsObj.addRecordDnsServer(optionsDns): flagError = True break # Поиск ptr записи dataIP = self.servDnsObj.getDomainAndZoneFromIP(ip) hostNameTmp, PTRDomainName, zoneNameTmp = dataIP # Находим ptr запись в DNS recData = self.servDnsObj.searchAllDomainNamesInLDAP(\ PTRDomainName) # Находит ip на основании имени хоста в обратной зоне # Удаляемые ip в обратной зоне deleteIP = self.servDnsObj.searchIPForHostInReverse(\ fullDomainName) # Флаг создания обратной записи flagCreatePTR = True if recData: if recData[0][0][1].has_key('pTRRecord'): hostList = recData[0][0][1]['pTRRecord'] # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x,\ y.split("."))) hostList = map(lambda x: delDot(x),hostList) if hostname in hostList: deleteIP = filter(lambda x: x!=ip, deleteIP) flagCreatePTR = False else: deleteIP.append(ip) deleteIP = list(set(deleteIP)) # Удаляем PTR записи в обратной зоне for delIP in deleteIP: if not self.servDnsObj.delRecordDnsServer(\ {"ip":delIP},\ False): flagError = True break # Создание PTR записи if flagCreatePTR: optionsDns = {"t":"ptr", "ip":ip, "host":fullDomainName} if not self.servDnsObj.addRecordDnsServer(optionsDns): flagError = True break if flagError: # Предупреждение хост существует self.printWARNING(_("Record %s exists in DNS")\ %fullDomainName) self.printWARNING(_("Can not create static host %s")\ %fullDomainName) break else: self.printERROR(_("Can not create static host")) self.printERROR(_("Can not found network for ip %s")%ip+\ " " + _("in config file %s")\ %dhcpObj.nameConfigFile) flagError = True break if flagError: return False return True def stopDhcp(self): """Остановка dhcpd""" if self.getRunService("dhcp"): textLines = self.execProg("/etc/init.d/dhcpd stop") if textLines == False: self.printNotOK(_("Stopping") + " " + "dhcpd" + " ...") return False return True def restartDhcp(self): """Рестарт dhcpd""" if self.getRunService("dhcp"): textLines = self.execProg("/etc/init.d/dhcpd restart") else: textLines = self.execProg("/etc/init.d/dhcpd start") if textLines == False: self.printNotOK(_("Starting") + " " + "dhcpd" + " ...") return False return True def printErrConfig(self, dhcpObj, net): """Вывод ошибки диапазона адресов в конфигурационном файле""" self.printERROR(_("Incorrect 'range' in config file %s")\ %dhcpObj.nameConfigFile) self.printERROR(_("Section 'subnet %s'")%net) def isNotExistsStaticMAC(self, mac, dhcpObj=False): """Проверяю существование mac адреса в статических хостах""" if not dhcpObj: dhcpObj = dncpTxt() dataHosts = dhcpObj.getDataInAllHost() getPar = lambda opt, data: map(lambda x: opt in x[1].keys() and\ (x[0],x[1][opt]) or (), data) flagCorrect = True staticMACs = getPar('hardwareethernet', dataHosts) for data in staticMACs: if not data: break hostname, stMAC = data if mac == stMAC[0]: self.printERROR(_("Found static host %s")%hostname +\ " mac %s" %mac +" " + _("in config file %s")\ %dhcpObj.nameConfigFile) flagCorrect = False break return flagCorrect def nets24ToMinIpAndMaxIp(self, startIpNumber, endIpNumber): """По минимальному и максимальному номеру ip получаем сети /24""" getOctList = lambda x: (x >> 24, x >> 16 & 255, x >> 8 & 255, x & 255) twoOctet = None nets24 = [] for i in range(startIpNumber,endIpNumber): tmpOctet = i >> 8 & 255 if twoOctet != tmpOctet: twoOctet = tmpOctet nets24.append(getOctList(i)) return nets24 def nets24ToIpAndMask(self, net): """По ip и маске сети (net) получаем cписок сетей /24""" startIpNumber, endIpNumber = self.getMinAndMaxIpNumb(net) return self.nets24ToMinIpAndMaxIp(startIpNumber, endIpNumber) def isCorrectNetRange(self, net, listRangeNew, dhcpObj=False): """Проверяет корректность нового диапазона динамических адресов""" if not dhcpObj: dhcpObj = dncpTxt() # Минимальный и максимальный номер ip сети minNumber, maxNumber = self.getMinAndMaxIpNumb(net) flagCorrect = True # Проверка на сеть try: minIp, maxIp = sorted([self.getNumberIP(listRangeNew[0]), self.getNumberIP(listRangeNew[1])]) if minIp == maxIp: flagCorrect = False except: flagCorrect = False if flagCorrect and (minIp == 0 or maxIp == 0): flagCorrect = False isRange = lambda n, minN, maxN: minN<=n<=maxN if flagCorrect: # Проверка на попадание в диапазон сети if not (isRange(minIp,minNumber,maxNumber) and\ isRange(maxIp,minNumber,maxNumber)): flagCorrect = False if not flagCorrect: self.printERROR(_("Incorrect range %s")%",".join(listRangeNew) +\ " " + _("for network %s")%net) return False netList = self.nets24ToMinIpAndMaxIp(minNumber, maxNumber) strNetList = map(lambda x: ".".join(map(lambda y: str(y), x[0:3])), netList) # Проверка на статические хосты dataHosts = dhcpObj.getDataInAllHost() getPar = lambda opt, data: map(lambda x: opt in x[1].keys() and\ (x[0],x[1][opt]) or (), data) staticIPs = getPar('fixed-address', dataHosts) for data in staticIPs: if not data: break hostname, stIP = data stIP = stIP[0] if stIP.rpartition(".")[0] in strNetList: try: numIP =self.getNumberIP(stIP) except: self.printERROR(_("Incorrect 'fixed-address %s'") %stIP +\ " " + _("in config file %s") %dhcpObj.nameConfigFile) flagCorrect = False break if isRange(numIP, minIp, maxIp): self.printERROR(\ _("Incorrect range %s")%",".join(listRangeNew) +\ " " + _("for network %s")%net) self.printERROR(_("Exists static host %s") %hostname+\ " ip %s "%stIP +_("in config file %s")\ %dhcpObj.nameConfigFile) flagCorrect = False break return flagCorrect def isCorrectDynamicIP(self, host, ip, dhcpObj=False, printErr=True): """Проверяет имя хоста и ip при добавлении при помощи демона""" flagError = False if not dhcpObj: dhcpObj = dncpTxt() dataNets = dhcpObj.getDataInAllSubnet() dataHosts = dhcpObj.getDataInAllHost() getPar = lambda opt, data: map(lambda x: opt in x[1].keys() and\ (x[0],x[1][opt]) or (), data) ranges = getPar('range', dataNets) try: numbIp = self.getNumberIP(ip) except: if printErr: self.printERROR(_("IP address %s incorrect")%ip) return (False, True) if not ranges: if printErr: self.printERROR(_("Can not found 'range' in config file %s")\ %dhcpObj.nameConfigFile) return (False, True) # Флаг корректности ip flagCorrect = False # Флаг ошибки в конфигурационном файле flagErrorConfig = False # n в диапазоне isRange = lambda n, minN, maxN: minN<=n<=maxN # Проверка на диапазон for data in ranges: flagCorrect = False if not data: break ipNet, listRange = data try: minIp, maxIp = sorted([self.getNumberIP(listRange[0]), self.getNumberIP(listRange[1])]) except: flagErrorConfig = True break if minIp == maxIp: flagErrorConfig = True break if isRange(numbIp, minIp, maxIp): flagCorrect = True break # Если ошибка в конфигурационном файле if flagErrorConfig: flagError = True if printErr: self.printErrConfig(dhcpObj, ipNet) else: # Проверка на статические хосты staticIPs = getPar('fixed-address', dataHosts) # Найден ли статический хост foundStatHost = False for data in staticIPs: if not data: break hostname, stIP = data # Если совпадают имя хоста и ip c конфигурационным файлом if host == hostname and stIP[0] == ip: foundStatHost = True flagCorrect = False break # Если совпадает хост if host == hostname: foundStatHost = True flagCorrect = False flagError = True if printErr: self.printERROR(_("ERROR") + ": ("+\ "host - %s"%host + ", " + "ip - %s"%ip+\ ") " + _("found a static host %s") %host+" " +\ _("in config file %s") %dhcpObj.nameConfigFile) break # Если совпадает ip if stIP[0] == ip: foundStatHost = True flagCorrect = False flagError = True if printErr: if printErr: self.printERROR(_("ERROR") + ": ("+\ "host - %s"%host + ", " + "ip - %s"%ip+\ ") " + _("found a static ip %s") %ip+" " +\ _("in config file %s") %dhcpObj.nameConfigFile) break if not foundStatHost and not flagCorrect: # Если не найден статический хост и если ip не найден\ # в диапазонах динамических ip существующих сетей flagError = True if printErr: self.printERROR(\ _("Can not found %s in dynamic ip range") %ip + " " +\ _("in config file %s") %dhcpObj.nameConfigFile) return (flagCorrect, flagError) def isCorrectStaticIP(self, ip, dhcpObj=False): """Проверяет ip на существующие сети и диапазон динамических адресов""" if not dhcpObj: dhcpObj = dncpTxt() dataNets = dhcpObj.getDataInAllSubnet() dataHosts = dhcpObj.getDataInAllHost() getPar = lambda opt, data: map(lambda x: opt in x[1].keys() and\ (x[0],x[1][opt]) or (), data) ranges = getPar('range', dataNets) if not ranges: self.printERROR(_("Can not found 'range' in config file %s")\ %dhcpObj.nameConfigFile) return False nets = getPar('mask', dataNets) if not nets: self.printERROR(\ _("Can not found 'subnet' and 'netmask' in config file %s")\ %dhcpObj.nameConfigFile) return False numbIp = self.getNumberIP(ip) # n в диапазоне isRange = lambda n, minN, maxN: minN<=n<=maxN # Проверка на сети # Флаг, ip найден в одной из сетей flagFoundIpInNet = False for net in nets: ipNet, ipMask = net minIp,maxIp = self.getMinAndMaxIpNumb(ipNet, ipMask[0]) if isRange(numbIp, minIp, maxIp): flagFoundIpInNet = True break if not flagFoundIpInNet: self.printERROR(_("Can not found %s in networks") %ip + " " +\ _("in config file %s")%dhcpObj.nameConfigFile) return False # Проверка на диапазон for rang in ranges: ipNet, listRange = rang if not listRange: continue minIp, maxIp = sorted([self.getNumberIP(listRange[0]), self.getNumberIP(listRange[1])]) if minIp == maxIp: self.printErrConfig(dhcpObj, ipNet) return False if isRange(numbIp, minIp, maxIp): self.printERROR(_("Found %s in dynamic ip range")%ip+" "+\ _("in config file %s")%dhcpObj.nameConfigFile) return False # Проверка на статические хосты if dataHosts: staticIPs = getPar('fixed-address', dataHosts) for data in staticIPs: if not data: break hostname, stIP = data if ip == stIP[0]: self.printERROR(_("Found static host %s")%hostname +\ " %s" %ip +" " + _("in config file %s")\ %dhcpObj.nameConfigFile) return False return True def isCorrectIPRangeListAndSort(self, net, ranges): """Проверяет на коректность диапазон сетевых адресов""" if len(ranges)!=2: return [] # Минимальный и максимальный номер ip сети minNumber, maxNumber = self.getMinAndMaxIpNumb(net) ipA, ipB = ranges minIpRanges, maxIpRanges = sorted([self.getNumberIP(ipA), self.getNumberIP(ipB)]) if minIpRanges == maxIpRanges: return [] # Не в диапазоне isNotRange = lambda n, minN, maxN: nmaxN # Проверка на одну сеть if isNotRange(minIpRanges, minNumber, maxNumber) or\ isNotRange(maxIpRanges, minNumber, maxNumber): return [] # Проверка на коректность сетевых адресов if filter(lambda x: not self.isCorrectStringNet(x, False), (ipA, ipB)): return [] return [self.getIPinNumber(minIpRanges),self.getIPinNumber(maxIpRanges)] def createLogFile(self): """Создание файла лога или если нужно изменение владельца файла лога""" import cl_log # Полное имя файла лога (путь плюс имя файла) logFullFile = os.path.join(cl_log.log.logDir, self.errorLogFile) if not os.path.exists(cl_log.log.logDir): try: os.makedirs(cl_log.log.logDir) except: self.printERROR(_("Can not create %s")%cl_log.log.logDir) return False else: # Создаем файловый объект fileObj = cl_profile._file() dMode, dUid, dGid = fileObj.getModeFile(cl_log.log.logDir) if dMode != 0755: try: os.chmod(cl_log.log.logDir,0755) except: self.printERROR(_("Can not set mode 0755 for %s")\ %cl_log.log.logDir) return False if dUid !=0 or dGid !=0: try: os.chown(cl_log.log.logDir, 0, 0) except: self.printERROR(\ _("Can not change owner (root:root) in %s")\ %cl_log.log.logDir) return False uidAndGid = self.getUserUidAndGid("dhcp") if not uidAndGid: return False uid, gid = uidAndGid if os.path.exists(logFullFile): # Создаем файловый объект fileObj = cl_profile._file() fMode, fUid,fGid = fileObj.getModeFile(logFullFile) # Если необходимо меняем владельца if (fUid, fGid)!=(uid, gid): try: os.chown(logFullFile, uid, gid) except: self.printERROR(_("Can not change owner (dhcp:dhcp) in %s")\ %logFullFile) return False else: try: self.createUserFile(logFullFile, "", uid, gid) except: self.printERROR(_("Can not create %s")%logFullFile) return False if not os.access(logFullFile, os.W_OK): self.printERROR(_("Can not access in %s")%logFullFile) return False return True def getMacInIp(self, ip): """Находит mac адрес по ip адресу""" for iface in cl_utils.getInterfaces(): mac,iface_ip = cl_utils.getMac(iface),cl_utils.getIp(iface) if iface_ip == ip and mac: return mac.lower() return "" def setupDhcpServer(self, options): """Начальная настройка DHCP сервиса""" # Принудительная установка forceOptions = False minKeys = [] if options.has_key("f"): forceOptions = True minKeys = ["f"] # Создаем объект переменных self.createClVars() if self.clVars.Get("sr_dns_set") != "on": self.printERROR(_("DNS service is not setuped")) self.printWARNING(_("Setup DNS service")) self.printWARNING(" cl-setup dns") return False # В случае если сервер установлен if self.clVars.Get("sr_dhcp_set") == "on" and not forceOptions: self.printWARNING (_("WARNING") + ": " +\ _("DHCP server is configured")+ ".") return True # Необходим ли LDAP flagLdap = False # находим установленные сервисы servInstalled = self.getServiceSetup() bakupObj = servLdap() if servInstalled: listServicesLDAP = list(set(servInstalled)-\ set(bakupObj.notLdapServices)) if listServicesLDAP: flagLdap = True optKeys = options.keys() minKeys += ["net", "router", "range", "dnames", "dnsip"] # Проверка на наличие всех нужных опций if not set(minKeys)<=set(optKeys): notFoundKeys = list(set(minKeys)-set(optKeys)) notFoundKeys = map(lambda x: len(x)>1 and '"--%s"'%x or '"-%s"'%x,\ notFoundKeys) self.printERROR(_("Not enough command line options: %s")\ %", ".join(notFoundKeys)) return False IPs = self.clVars.Get("os_net_ip").split(',') if not any(IPs): self.printERROR(_("Can not found ip in net interfaces")) return False if not forceOptions: # предупреждение при выполнении этой программы будут изменены # конфигурационные файлы сервиса DHCP (программa dhcpd) self.printWARNING (_("WARNING") + ": " + _("Executing of the program will change") + " " + _("the configuration files of DHCP service") +" ("+ _("program dhcpd") + ")." ) # если вы готовы продолжить работу программы нажмите Y если нет n messDialog = \ _("If you are ready to continue executing the program") + ", "+\ _("input 'yes'") +", "+ _("if not 'no'") if not self.dialogYesNo(messDialog): return True else: # делаем backup if flagLdap: # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False if not bakupObj.backupServer(): return False else: if not bakupObj.backupNotLdap(): return False # Создаем файл вывода ошибок скрипта dhcp if not self.createLogFile(): return False # Удаляем переменные сервиса в ini файлах self.deleteServiceVarsInFile("dhcp") # Если существует конфигурационный файл if os.path.exists(dncpTxt.nameConfigFile): # Удаляем в нем все статические хосты и сети dhcpObj = dncpTxt() if not dhcpObj.deleteAllNetAndHosts(): return False # Cоздаем объект переменные self.createClVars() # Удаляем из автозапуска демона if not self.delDaemonAutostart("dhcpd"): return False # останавливаем сервис dhcp if not self.stopServices(["dhcp"]): return False self.clVars.Set("cl_pass_service","dhcp") self.clVars.Write("sr_dhcp_set","off") # Устанавливаем переменные if self.isServiceSetup("dns"): ldapParser = iniLdapParser() adminDnsPw = ldapParser.getVar("dns","PASS") if not adminDnsPw: self.printERROR(_("Not found password from service %s")%"DNS") return False self.clVars.Set("ld_dns_pw", adminDnsPw, True) # Cоздаем объект профиль устанавливая директорию dhcp для # файлов профилей if not self.applyProfilesFromService('dhcp'): return False if flagLdap: # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер if not self.runLdapServer(): return False # Создаем текстовый блок в конфигурационном файле для новой сети netOptions = {} if options.has_key("net"): netOptions["net"] = options["net"] if options.has_key("router"): netOptions["router"] = options["router"] if options.has_key("dnames"): netOptions["dnames"] = options["dnames"] if options.has_key("dnsip"): netOptions["dnsip"] = options["dnsip"] if options.has_key("range"): netOptions["range"] = options["range"] if not self.createNetDhcpServer(netOptions, False): return False # Добавляем в статические хосты имя текущего хоста hostname = self.clVars.Get("os_net_hostname") if hostname: domainNames = map(lambda x: x.lower(), options["dnames"].split(",")) domainNames = self.unicList(domainNames) domain = domainNames[0] fullHostNameServer = "%s.%s"%(hostname,domain) IPs = filter(None,self.clVars.Get("os_net_ip").split(",")) if not any(IPs): self.printERROR(_("Can not found ip in net interfaces")) return False ipServer = "" #trNet = options["net"].rpartition(".")[0] for ip in IPs: if self.isRangeNet(ip, options["net"]): ipServer = ip break macServer = "" if ipServer: macServer = self.getMacInIp(ipServer) if ipServer and macServer: flagCreateDNSRecord = True flagDeleteARecord = False flagDeletePTRRecord = False flagFoundARecord = False # Ищем A запись в DNS recData = self.servDnsObj.searchDomainNameInLDAP(\ fullHostNameServer) if recData and recData[0][0][1].has_key('aRecord'): flagFoundARecord = True if ipServer in recData[0][0][1]['aRecord']: flagCreateDNSRecord = False else: flagDeleteARecord = True # Ищем PTR запись в DNS dataIP = self.servDnsObj.getDomainAndZoneFromIP(ipServer) hostNameTmp, PTRDomainName, zoneNameTmp = dataIP # Находим ptr запись в DNS recData = self.servDnsObj.searchAllDomainNamesInLDAP(\ PTRDomainName) if recData and recData[0][0][1].has_key('pTRRecord'): if not flagCreateDNSRecord: hostList = recData[0][0][1]['pTRRecord'] # Удаляет лишние точки в названии delDot = lambda y: ".".join(filter(lambda x: x,\ y.split("."))) hostList = map(lambda x: delDot(x),hostList) if not fullHostNameServer in hostList: flagCreateDNSRecord = True flagDeletePTRRecord = True if flagFoundARecord: flagDeleteARecord = True else: flagCreateDNSRecord = True flagDeletePTRRecord = True if flagFoundARecord: flagDeleteARecord = True if flagDeleteARecord: # Удаляем A запись if not self.servDnsObj.delRecordDnsServer( {"host":fullHostNameServer}, False): return False if flagDeletePTRRecord: # Удаляем PTR запись if not self.servDnsObj.delRecordDnsServer(\ {"ip":ipServer}, False): return False hostOptions = {"host":hostname, "ip":ipServer, "mac":macServer} if not self.createHostDhcpServer(hostOptions, False,\ flagCreateDNSRecord): return False # Создаем resolv.conf self.createResolvFile(options["dnames"]) # Модификация hosts if hostname: self.createHostsFile(fullHostNameServer) # Устанавливаем автозапуск демона if not self.setDaemonAutostart("dhcpd"): return False # Запишем, что сервис установлен self.clVars.Write("sr_dhcp_set","on") self.printOK(_("dhcpd service configured") + " ...") return True class tsOpt(cl_base.opt): """Класс для обработки параметров и вывода help Параметры: helpObj объект-справка содержащий необходимые опции parBeforeService дополнительные необходимые параметры перед указанным сервисом. (например "group" или "user") optService проверять хвост командной строки на наличие сервиса notOptError выдавать ошибку при отсутствии опций командной строки lastOpt одно произвольное значение в хвосте командной строки """ def __init__(self, helpObj, parBeforeService, optService=True, notOptError=False, lastOpt=False): # последний параметр является сервисом service = sys.argv[-1:][0].rstrip() # от cl_help получаем короткие и длинные опции if service in helpObj.allServ: shortOpt, longOpt = helpObj.getAllOpt('all', helpObj.relServices[service]) else: shortOpt,longOpt = helpObj.getAllOpt('all', helpObj.relOptions['h']) # вызвать конструктор объекта, распознающего опции cl_base.opt.__init__(self,shortOpt,longOpt) self.nameParams = parBeforeService + ['service'] self.sysArgv = sys.argv[1:] self.helpObj = helpObj self.__iter = 0 self.opt = {} self.params = {} self.getopt() # Обработка help self.flagHelp = False # Ошибка в опциях self.errorOpt = False # определяем есть ли среди опций опции, которые влияют на показ # опциональных разделов (метод пересечения множеств) helpopt = \ tuple(set(self.opt.keys()).intersection(helpObj.relOptions.keys())) #Если есть опции help if len(helpopt) > 0: print helpObj.getHelp(helpObj.relOptions[helpopt[0]]) self.flagHelp = True #Если нет хвостов elif not self.params: if optService or lastOpt: print helpObj.getHelp(helpObj.relOptions['h']) self.flagHelp = True else: if self.params.has_key('service'): if lastOpt: pass elif not (self.params['service'] in helpObj.allServ): self.handlerErrOpt() self.flagHelp = True if not self.flagHelp and len(self.nameParams) != self.__iter: self.handlerErrOpt() self.flagHelp = True else: self.handlerErrOpt() self.flagHelp = True # В случае отсутствия опций командной строки if notOptError and not self.opt and self.params.has_key('service'): self.printErrorNotOpt() self.flagHelp = True def printErrorNotOpt(self): """Сообщение в случае отсутствия опций""" print _("Options are absent.") def handlerOpt(self,option,value): # Обработчик (опция значение) #print option, value shortOpt = self.helpObj.getShortOpt(option) if not shortOpt: shortOpt = option if not shortOpt in self.opt: self.opt[shortOpt] = value def handlerErrOpt(self): # Обработчик ошибок self.errorOpt = True argv = " ".join(sys.argv[1:]) print _("Unrecognized option") + ' "' + argv + '"\n' + \ _("Try") + ' "' + sys.argv[0].split("/")[-1] + ' --help" ' +\ _("for more information.") def handlerParam(self,param): # Обработчик хвостов (значение) self.__iter += 1 if self.__iter<=len(self.nameParams): self.params[self.nameParams[self.__iter-1]] = param