10 changed files with 1899 additions and 23 deletions
-
2README
-
5pym/cl_libserver.py
-
26pym/cl_template.py
-
17pym/cl_utils.py
-
1pym/server/__init__.py
-
432pym/server/ldap.py
-
564pym/server/services.py
-
138pym/server/share.py
-
354pym/server/users.py
-
383pym/server/utils.py
@ -0,0 +1 @@ |
|||
|
@ -0,0 +1,432 @@ |
|||
#-*- coding: utf-8 -*- |
|||
|
|||
# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
|
|||
import os |
|||
from ldap import LDAPError, MOD_REPLACE, MOD_ADD, SCOPE_SUBTREE, SCOPE_ONELEVEL |
|||
from ldif import LDIFParser, LDIFWriter |
|||
import cStringIO, StringIO |
|||
from cl_utils import _error |
|||
from cl_print import color_print |
|||
from cl_template import template, iniParser |
|||
from cl_ldap import ldapFun |
|||
from server.share import shareVars |
|||
from server.utils import genSleep, stringIsJpeg |
|||
# Перевод модуля |
|||
import cl_lang |
|||
tr = cl_lang.lang() |
|||
tr.setLocalDomain('cl_lib') |
|||
tr.setLanguage(sys.modules[__name__]) |
|||
|
|||
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 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(ldapFun): |
|||
'''Объект для работы с LDAP сервером''' |
|||
def __init__(self, dnUser, password): |
|||
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 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 |
|||
|
|||
|
|||
class iniLdapParser(iniParser): |
|||
"""Класс для работы c ini-файлом ldap""" |
|||
def __init__(self): |
|||
# название ini файла |
|||
self.nameIniFile = "/etc/calculate/calculate.ldap" |
|||
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 ldap(_error, color_print, shareVars): |
|||
"""Общие методы для работы с LDAP для серверных программ""" |
|||
|
|||
# DN сервисов относительно базового |
|||
ServicesDN = "ou=Services" |
|||
# Переменная объект Vars |
|||
clVars = False |
|||
# Переменная объект ldapFunction |
|||
ldapObj = False |
|||
# Переменная соединение с LDAP сервером |
|||
conLdap = False |
|||
# Базовый DN LDAP сервера |
|||
baseDN = False |
|||
|
|||
def addDN(self, *arg): |
|||
"""Складывает текстовые элементы DN""" |
|||
DNs = [] |
|||
for dn in arg: |
|||
if dn: |
|||
DNs.append(dn) |
|||
return ','.join(DNs) |
|||
|
|||
@adminConnectLdap |
|||
def searchLdapDN(self, name, relDN, attr, retAttr=None): |
|||
"""Находит DN в LDAP""" |
|||
DN = self.addDN(relDN,self.baseDN) |
|||
#searchScope = SCOPE_SUBTREE |
|||
searchScope = SCOPE_ONELEVEL |
|||
searchFilter = "%s=%s" %(attr,name) |
|||
retrieveAttributes = retAttr |
|||
resSearch = self.ldapObj.ldapSearch(DN, searchScope, |
|||
searchFilter, retrieveAttributes) |
|||
return resSearch |
|||
|
|||
@adminConnectLdap |
|||
def addEntry(self, DN, entry, errorMessage): |
|||
"""Добавление узла в LDAP""" |
|||
try: |
|||
self.conLdap.add_s(DN, entry) |
|||
except LDAPError, e: |
|||
self.printERROR(_("LDAP Error") + ": " + e[0]['desc'].strip()) |
|||
self.printERROR(errorMessage) |
|||
return False |
|||
return True |
|||
|
|||
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 = genSleep() |
|||
while ldapObj.getError(): |
|||
try: |
|||
# Задержка |
|||
wait.next() |
|||
except StopIteration: |
|||
break |
|||
# Очистка ошибки |
|||
_error.error = [] |
|||
ldapObj = ldapFunction(adminDn, adminPw) |
|||
if ldapObj.getError(): |
|||
# Удаляем одинаковые ошибки |
|||
listError = [] |
|||
for e in ldapObj.error: |
|||
if not e in listError: |
|||
listError.append(e) |
|||
_error.error = listError |
|||
self.printERROR (_("LDAP connect error") + ": " +\ |
|||
ldapObj.getError().strip()) |
|||
return False |
|||
# Устанавливаем у объекта соединение и объект LDAP функций |
|||
self.ldapObj = ldapObj |
|||
self.conLdap = ldapObj.conLdap |
|||
return True |
|||
|
|||
def connectToLDAP(self, adminDn, adminPw): |
|||
"""Подключаемся к LDAP - для внешних программ запускающихся не от root |
|||
""" |
|||
ldapObj = ldapFunction(adminDn, adminPw) |
|||
# Генератор задержек |
|||
wait = genSleep() |
|||
while ldapObj.getError(): |
|||
try: |
|||
# Задержка |
|||
wait.next() |
|||
except StopIteration: |
|||
break |
|||
# Очистка ошибки |
|||
_error.error = [] |
|||
ldapObj = ldapFunction(adminDn, adminPw) |
|||
if ldapObj.getError(): |
|||
# Удаляем одинаковые ошибки |
|||
listError = [] |
|||
for e in ldapObj.error: |
|||
if not e in listError: |
|||
listError.append(e) |
|||
_error.error = listError |
|||
self.printERROR (_("LDAP connect error") + ": " +\ |
|||
ldapObj.getError().strip()) |
|||
return False |
|||
# Устанавливаем у объекта соединение и объект LDAP функций |
|||
self.ldapObj = ldapObj |
|||
self.conLdap = ldapObj.conLdap |
|||
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 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 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 |
|||
|
|||
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) |
|||
ldifTemplate = FD.read() |
|||
FD.close() |
|||
clTempl = template(self.clVars) |
|||
# Применяем условия к шаблону |
|||
ldifTemplate = clTempl.applyTermsTemplate(ldifTemplate, ldifFile) |
|||
# Заменяем переменные в шаблоне |
|||
ldifTemplate = clTempl.applyVarsTemplate(ldifTemplate, ldifFile) |
|||
return ldifTemplate |
|||
|
|||
@adminConnectLdap |
|||
def delDN(self, relDN): |
|||
"""Удаляет одиночный DN""" |
|||
DN = self.addDN(relDN,self.baseDN) |
|||
try: |
|||
self.conLdap.delete_s(DN) |
|||
except LDAPError, e: |
|||
self.printERROR(e[0]['desc']) |
|||
return False |
|||
return True |
|||
|
|||
@adminConnectLdap |
|||
def deleteDN(self, relDelDN): |
|||
"""Удаляет DN и все внутренние элементы""" |
|||
delDN = self.addDN(relDelDN, self.baseDN) |
|||
delListDN=[] |
|||
try: |
|||
dnList = self.conLdap.search_s(delDN, |
|||
SCOPE_SUBTREE, |
|||
'(objectclass=*)', |
|||
['']) |
|||
except 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 LDAPError, e: |
|||
self.printERROR("deleteDN: "+e[0]['desc']) |
|||
return False |
|||
return True |
|||
|
|||
@adminConnectLdap |
|||
def fullElementDNtoText(self, relDN="", ldapFilter='(objectclass=*)'): |
|||
"""Выводит все внутренние элементы DN виде текста""" |
|||
DN = self.addDN(relDN, self.baseDN) |
|||
listDN=[] |
|||
try: |
|||
dnList = self.conLdap.search_s(DN, |
|||
SCOPE_SUBTREE, |
|||
ldapFilter,None) |
|||
except 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 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 stringIsJpeg(photoData): |
|||
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 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((MOD_REPLACE, 'jpegPhoto', photoData)) |
|||
else: |
|||
modAttrs.append((MOD_ADD, 'jpegPhoto', photoData)) |
|||
userDN = self.addDN("%s=%s"%(attr,userName),self.relUsersDN) |
|||
if not self.modAttrsDN(userDN, modAttrs): |
|||
return False |
|||
return True |
|||
|
|||
def searchService(self): |
|||
"""Поиск DN сервиса""" |
|||
name, value = self.relServDN.split('=') |
|||
resSearch = self.searchLdapDN(value, self.ServicesDN, name) |
|||
return resSearch |
@ -0,0 +1,564 @@ |
|||
#-*- coding: utf-8 -*- |
|||
|
|||
# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
|
|||
import os |
|||
import sys |
|||
import types |
|||
import time |
|||
from cl_print import color_print |
|||
from cl_template import template |
|||
from server.utils import execProg |
|||
from server.users import users |
|||
# Перевод модуля |
|||
import cl_lang |
|||
tr = cl_lang.lang() |
|||
tr.setLocalDomain('cl_lib') |
|||
tr.setLanguage(sys.modules[__name__]) |
|||
|
|||
class services(color_print): |
|||
"""Общие методы для серверных программ, |
|||
|
|||
Методы для работы с сервисами""" |
|||
|
|||
# Переменная объект Vars |
|||
clVars = False |
|||
# Сервисы и демоны |
|||
servicesDaemons = {"ldap":["slapd"], |
|||
"unix":["slapd"], |
|||
"samba":["samba"], |
|||
"mail":["postfix","dovecot"], |
|||
"mail_relay":["postfix"], |
|||
"jabber":["ejabberd"], |
|||
"ftp":["proftpd"], |
|||
"proxy":["squid"], |
|||
"dns":["named"], |
|||
"dhcp":["dhcpd"]} |
|||
|
|||
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 _getDefaultRunlevelDaemons(self): |
|||
"""Получаем всех демонов в default уровне""" |
|||
execStr = "rc-update show" |
|||
textLine = 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 = 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 = 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 = execProg("/etc/init.d/slapd start") |
|||
if textLines == False: |
|||
self.printNotOK(_("Starting LDAP")+ " ...") |
|||
return False |
|||
else: |
|||
return True |
|||
|
|||
def restartLdapServer(self): |
|||
"""Запускает LDAP сервер""" |
|||
textLines = execProg("/etc/init.d/slapd restart") |
|||
if textLines == False: |
|||
self.printNotOK(_("Restarting LDAP")+ " ...") |
|||
return False |
|||
else: |
|||
return True |
|||
|
|||
def stopLdapServer(self): |
|||
"""Останавливает LDAP сервер""" |
|||
textLines = execProg("/etc/init.d/slapd stop") |
|||
if textLines == False: |
|||
self.printNotOK(_("Stopping LDAP")+ " ...") |
|||
return False |
|||
else: |
|||
return True |
|||
|
|||
def getALLServices(self): |
|||
"""Получаем все сервисы которые описаны в шаблонах""" |
|||
# путь к директории шаблонов |
|||
templatePath = self.clVars.Get("cl_template_path")[0] |
|||
data = os.listdir(templatePath) |
|||
service = [] |
|||
for fileData in data: |
|||
if os.path.isdir(os.path.join(templatePath, 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 getTemplatePath(self, nameService): |
|||
"""список накладываемых профилей в зависимости от сервиса""" |
|||
profpath = [] |
|||
profPaths = ['/usr/lib/calculate/calculate-server/profile/%s'\ |
|||
%nameService, |
|||
'/var/calculate/remote/server-profile/%s'%nameService, |
|||
'/var/calculate/server-profile/%s'%nameService] |
|||
for profPath in profPaths: |
|||
if os.path.exists(profPath): |
|||
profpath.append(profPath) |
|||
return profpath |
|||
|
|||
def applyTemplatesFromService(self, service, verbose=False): |
|||
"""Применяем шаблоны для данного сервиса""" |
|||
# Пути к шаблонам для сервиса |
|||
profPaths = self.getTemplatePath(service) |
|||
# Устанавливаем пути к шаблонам для сервиса |
|||
self.clVars.Set("cl_template_path", profPaths, True) |
|||
clTempl = template(self.clVars) |
|||
# Объединяем шаблоны |
|||
data = clTempl.applyTemplates() |
|||
if clTempl.getError(): |
|||
self.printERROR(clTempl.getError()) |
|||
return False |
|||
else: |
|||
if verbose and type(data) == types.TupleType: |
|||
dirs, files = data |
|||
return files |
|||
return True |
|||
|
|||
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 = 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 = 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 = 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=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 = 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 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 = 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")} |
|||
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 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 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 initialChecks(self, service, printError=True): |
|||
"""Начальная проверка перед запуском методов сервиса""" |
|||
# Создаем объект переменных |
|||
self.createClVars() |
|||
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 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): |
|||
"""Создает сертификат""" |
|||
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) |
|||
# Объект для работы с пользователями |
|||
usersObj = users() |
|||
# получаем id и gid пользователя |
|||
uidAndGid = usersObj.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) |
|||
# генерируем название файла конфигурации |
|||
strData = time.strftime("%Y%m%d%H%M%S",time.localtime(time.time())) |
|||
cnfFile = "/tmp/%s.cnf" %strData |
|||
sslFile = "/usr/bin/openssl" |
|||
if not os.path.exists(sslFile): |
|||
self.printERROR(_("Can not found %s")%sslFile) |
|||
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 = execProg(\ |
|||
"%s req -new -x509 -nodes -config %s -days %s -out %s -keyout %s"\ |
|||
%(sslFile, cnfFile, sslDays, certFile, keyFile)) |
|||
# Удаление конфигурационного файла |
|||
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 = 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 |
@ -0,0 +1,138 @@ |
|||
#-*- coding: utf-8 -*- |
|||
|
|||
# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
|
|||
from cl_data import DataVars |
|||
from cl_print import color_print |
|||
# Перевод модуля |
|||
import cl_lang |
|||
tr = cl_lang.lang() |
|||
tr.setLocalDomain('cl_lib') |
|||
tr.setLanguage(sys.modules[__name__]) |
|||
|
|||
class shareVars: |
|||
"""Общие методы для классов модулей серверных программ""" |
|||
# Переменная объект Vars |
|||
clVars = False |
|||
|
|||
def createClVars(self, clVars=False, returnImportVar=False): |
|||
"""Создает объект Vars""" |
|||
# Словарь импортируемых переменных из ini Файлов |
|||
dictImportVars = {} |
|||
if not clVars: |
|||
clVars = DataVars() |
|||
clVars.flServer() |
|||
dictImportVars = clVars.flIniFile() |
|||
# Устанавливаем у объекта объект Vars |
|||
self.clVars = clVars |
|||
if returnImportVar: |
|||
return dictImportVars |
|||
return True |
|||
|
|||
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 |
|||
|
|||
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 is 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 reloadDefaultVar(self, nameVar): |
|||
"""При получениии значения переменной снова |
|||
|
|||
вызывается метод заполнения переменной""" |
|||
self.clVars.Set(nameVar,"",True) |
|||
self.clVars.__getattribute__(nameVar).countFill = 0 |
|||
self.clVars.__getattribute__(nameVar).fillStart = True |
|||
return True |
|||
|
|||
class servicesAPI(color_print): |
|||
"""Методы сервисов используемые другими сервисами""" |
|||
# Путь к модулю сервера |
|||
__pathServer__ = "/usr/lib/calculate/calculate-server/pym" |
|||
# Названия импортированных классов |
|||
__imports_names__ = [] |
|||
# Импортированные классы |
|||
__imports_classes__ = {} |
|||
|
|||
def __getServiceObj__(self, serviceName): |
|||
"""Получаем объект сервиса""" |
|||
if not serviceName in __imports_names__: |
|||
try: |
|||
classImport = getattr(__import__("cl_ldap", globals(),\ |
|||
locals(),[]), serviceName) |
|||
except (ImportError, AttributeError): |
|||
self.printERROR(_("Can not found service class '%s'")\ |
|||
%serviceName) |
|||
return False |
|||
__imports_classes__[serviceName] = classImport |
|||
__imports_names__.append(serviceName) |
|||
retObj = classImport() |
|||
else: |
|||
retObj = __imports_classes__[serviceName]() |
|||
return retObj |
|||
|
|||
def searchUnixUser(self, userName, servUnixObj=None): |
|||
"""Поиск пользователя в LDAP ветке Unix сервиса""" |
|||
if not servUnixObj: |
|||
servUnixObj = self.__getServiceObj__("unix") |
|||
if not servUnixObj: |
|||
exit(1) |
|||
return servUnixObj.searchUnixUser(userName) |
|||
|
|||
def searchPasswdUser(self, userName, servUnixObj=None): |
|||
"""Поиск пользователя в /etc/passwd""" |
|||
if not servUnixObj: |
|||
servUnixObj = self.__getServiceObj__("unix") |
|||
if not servUnixObj: |
|||
exit(1) |
|||
return servUnixObj.searchPasswdUser(userName) |
|||
|
@ -0,0 +1,354 @@ |
|||
#-*- coding: utf-8 -*- |
|||
|
|||
# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
|
|||
import os |
|||
import sys |
|||
# Ввод pwd |
|||
import getpass |
|||
import types |
|||
from cl_utils import removeDir |
|||
from cl_print import color_print |
|||
from server.share import servicesAPI |
|||
from server.utils import rawInput, isCorrectStringNet, addInfoUser, addInfoGroup |
|||
# Перевод модуля |
|||
import cl_lang |
|||
tr = cl_lang.lang() |
|||
tr.setLocalDomain('cl_lib') |
|||
tr.setLanguage(sys.modules[__name__]) |
|||
|
|||
class users(color_print): |
|||
"""Общие методы для серверных программ, |
|||
|
|||
(работа с пользователями и группами)""" |
|||
|
|||
# Объект с методами доступа к другим сервисам |
|||
servicesAPIObj = servicesAPI() |
|||
|
|||
# Статические группы |
|||
staticGroups = {\ |
|||
'client':addInfoGroup('client', |
|||
'900', |
|||
'Client group', |
|||
'2801', |
|||
'2'), |
|||
'Domain Admins':addInfoGroup('Domain Admins', |
|||
'512', |
|||
'Domain Administrators', |
|||
'512', |
|||
'2'), |
|||
'Domain Users':addInfoGroup('Domain Users', |
|||
'513', |
|||
'Domain Users', |
|||
'513', |
|||
'2'), |
|||
'Domain Guests':addInfoGroup('Domain Guests', |
|||
'514', |
|||
'Domain Guests Users', |
|||
'514', |
|||
'2'), |
|||
'Domain Computers':addInfoGroup('Domain Computers', |
|||
'515', |
|||
'Domain Computers accounts', |
|||
'515', |
|||
'2'), |
|||
'Administrators':addInfoGroup('Administrators', |
|||
'544', |
|||
'Domain Members can fully \ |
|||
administer the computer/sambaDomainName', |
|||
'544', |
|||
'5', |
|||
"S-1-5-32-544"), |
|||
'Account Operators':addInfoGroup('Account Operators', |
|||
'548', |
|||
'Domain Users to manipulate \ |
|||
users accounts', |
|||
'548', |
|||
'5', |
|||
"S-1-5-32-548"), |
|||
'System Operators':addInfoGroup('System Operators', |
|||
'549', |
|||
'Domain System Operators', |
|||
'549', |
|||
'5', |
|||
"S-1-5-32-549"), |
|||
'Print Operators':addInfoGroup('Print Operators', |
|||
'550', |
|||
'Domain Print Operators', |
|||
'550', |
|||
'5', |
|||
"S-1-5-32-550"), |
|||
'Backup Operators':addInfoGroup('Backup Operators', |
|||
'551', |
|||
'Domain Members can bypass \ |
|||
file security to back up files', |
|||
'551', |
|||
'5', |
|||
"S-1-5-32-551"), |
|||
'Replicators':addInfoGroup('Replicators', |
|||
'552', |
|||
'Domain Supports file replication \ |
|||
in a sambaDomainName', |
|||
'552', |
|||
'5', |
|||
"S-1-5-32-552"), |
|||
} |
|||
# Статические пользователи |
|||
staticUsers = {\ |
|||
'client':addInfoUser('client', |
|||
'900', |
|||
'900', |
|||
'Client samba user'), |
|||
'admin':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 __restoreDelUser(self,userName,service,srcDir,message,unixObj=False): |
|||
"""Возвращаем данные удаленного пользователя""" |
|||
# Ищем Unix пользователя |
|||
searchUnixUser = self.servicesAPIObj.searchUnixUser(userName, unixObj) |
|||
# id пользователя |
|||
strUid = "" |
|||
if searchUnixUser: |
|||
strUid = searchUnixUser[0][0][1]['uidNumber'][0] |
|||
else: |
|||
resPasswd = self.servicesAPIObj.searchPasswdUser(userName, unixObj) |
|||
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 = dialogYesNo(message) |
|||
if dialogRes and dialogRes == True: |
|||
try: |
|||
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 |
|||
|
|||
def restorePathDelUser(self,userName,destDir,relDir,message,unixObj=False): |
|||
"""Восстанавливает директорию удаленного пользователя""" |
|||
removedDir = False |
|||
flagError = False |
|||
resRestore = self.__restoreDelUser(userName, relDir, |
|||