You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-utils-2.1-server/pym/cl_ldap.py

853 lines
32 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#-*- coding: utf-8 -*-
#Copyright 2008 Calculate Pack, http://www.calculate-linux.ru
#
# 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 popen2
import ldap
import cStringIO
from ldif import LDIFParser
import cl_base
import cl_profile
# Для подсчета символов
import termios, fcntl, struct
class iniLdapParser(cl_base.iniParser):
"""Класс для работы c ini-файлом ldap"""
def __init__(self):
# название ini файла
nameIniFile = "/etc/calculate2/calculate.ldap"
cl_base.iniParser.__init__(self,nameIniFile)
# права создаваемого ini-файла
self.setMode(0600)
pathIniFile = os.path.split(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_profile._error):
'''Объект для работы с LDAP сервером'''
def __init__(self, dnUser, password):
self.conLdap = False
# Получаем соединение с LDAP
try:
self.conLdap = self.__ldapConnect(dnUser, password)
except ldap.LDAPError, e:
self.setError(e[0]['desc'])
def __ldapConnect(self, dnUser, password):
"""Соединение с LDAP сервером"""
conLdap = ldap.initialize('ldap://localhost')
conLdap.simple_bind_s(dnUser, password)
return conLdap
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
return True
else:
self.setError(_("No connect to LDAP server"))
return False
Version = "calculate-server 0.0.1"
tr = cl_base.lang()
tr.setLanguage(sys.modules[__name__])
class cl_ldap(cl_profile._error, cl_profile.xmlShare):
def strOnTwoColumn(self, s1, s2):
return "%%-%ds%%s" % self.column_width % (\
s1+" ",s2)
def setColumnWidth(self, newwidth):
'''Установить ширину первой колонки при выводе справки.
Параметры:
newwidth новая ширина
'''
self.column_width = int(newwidth)
def getChapterNumber(self,NameChapter):
# Показать номер раздела по его имени
num = 0
for i in self.chapter:
if i[0] == NameChapter:
return num
num += 1
return False
def __init__(self, cmdName):
# ini файл
self.iniFile = "/etc/calculate2/calculate.ini"
self.column_width = 25
# Удаляем ненужный аттрибут класса cl_profile.xmlShare
self._createElement = False
delattr(self, "_createElement")
self.cmdName = cmdName
#короткие опции командной строки
self.shortOpt = []
#длинные опции командной строки
self.longOpt = []
#optEnd = ""
#if "user" in self.cmdName and not "mod" in self.cmdName:
#optEnd = _("user")
#elif "group" in self.cmdName and not "mod" in self.cmdName:
#optEnd = _("group")
servName = ""
if "user" in self.cmdName:
servName = _("user")
elif "group" in self.cmdName:
servName = _("group")
elif "setup" in self.cmdName:
servName = _("service")
self.chapter = [\
# расположение разделов на странице
# имя раздела, видимый или невидимый, кол. "\n" после
# названия раздела, кол. "\n" после раздела
("Copyright",False,0,2),
(_("Usage"),True,0,1),
("Function",False,0,2),
(_("Examples"),True,1,1),
(_("Options"),True,1,1),
(_("Services"),True,1,1),
(_("Informative output"),True,1,0),
]
self.chapterBloc = []
# разделы справки
for i in self.chapter:
self.chapterBloc.append("")
# имена используемых программ и их номера для доступа к переменным
# 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,
}
self.data = [\
# Options
{'progAccess':(3,),
'shortOption':"p",
'longOption':"password",
'optVal':"file",
'helpChapter':_("Options"),
'help':_("input user password")
},
{'progAccess':(6,),
'shortOption':"f",
'longOption':"force",
'helpChapter':_("Options"),
'help':_("forced setup service")
},
{'shortOption':"s",
'longOption':"set",
'optVal':"<name>=<val>",
'helpChapter':_("Options"),
'help':_("change enviroment values")
},
{'shortOption':"e",
'longOption':"env",
'optVal':"filter",
'helpChapter':_("Options"),
'help':_("show enviroment values (filter for type, all - no filter)")
},
# Services
{'helpChapter':_("Services"),
'help':self.strOnTwoColumn(" ldap", "ldap " + servName) + "\n"
},
{'helpChapter':_("Services"),
'help':self.strOnTwoColumn(" samba", "samba " + servName) + "\n"
},
##{'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
{'shortOption':"h",
'longOption':"help",
'helpChapter':_("Informative output"),
'help':_("display this help and exit")
},
{
#'progAccess':(3,),
'helpChapter':"Copyright",
'help':Version
},
# Использование
{
'progAccess':(3,),
'helpChapter':_("Usage"),
'help': self.cmdName + " " + " [" + _("options") + "] " + _("user") +\
" " + _("service")
},
{
'progAccess':(6,),
'helpChapter':_("Usage"),
'help': self.cmdName + " " + " [" + _("options") + "] "+\
" " + _("service")
},
{
'progAccess':(0,),
'helpChapter':"Function",
'help':_("Adds group in LDAP directory of service")
},
{
'progAccess':(1,),
'helpChapter':"Function",
'help':_("Deletes group from LDAP of directory of service")
},
{
'progAccess':(2,),
'helpChapter':"Function",
'help':_("Modifies group profiles from LDAP of directory of service")
},
{
'progAccess':(3,),
'helpChapter':"Function",
'help':_("Adds user in LDAP directory of service")
},
{
'progAccess':(4,),
'helpChapter':"Function",
'help':_("Deletes user from LDAP of directory of service")
},
{
'progAccess':(5,),
'helpChapter':"Function",
'help':_("Modifies user profiles from LDAP of directory of service")
},
{
'progAccess':(6,),
'helpChapter':"Function",
'help':_("Sets service in the system")
},
# Примеры
{
'progAccess':(0,),
'helpChapter':_("Examples"),
'help':" " + _("cl-groupadd -smfw guest\t # add group guest \
in services:\n\
\t\t\t\t # samba, mail, ftp, wiki.")
},
{
'progAccess':(1,),
'helpChapter':_("Examples"),
'help':" " + _("cl-groupdel -smfw guest\t # delete group \
guest in services:\n\
\t\t\t\t # samba, mail, ftp, wiki.""")
},
{
'progAccess':(2,),
'helpChapter':_("Examples"),
'help':""
},
{
'progAccess':(3,),
'helpChapter':_("Examples"),
'help':" " + "cl-useradd guest samba #" +_("add user guest in \
service samba") + ".\n"
},
{
'progAccess':(4,),
'helpChapter':_("Examples"),
'help': " " + _("cl-userdel -smfw guest\t # delete user \
guest in services:\n\
\t\t\t\t # samba, mail, ftp, wiki.""")
},
{
'progAccess':(5,),
'helpChapter':_("Examples"),
'help':""
},
{
'progAccess':(6,),
'helpChapter':_("Examples"),
'help':" " + "cl-setup samba #"+_("set service") + " samba " +\
_("in the system") + ".\n"
},
{
'helpChapter':_("Examples"),
'help':" " + self.cmdName + " --env boot #"+
_("show enviroment varibles which has type") + " 'boot'" + ".\n"
},
{
'helpChapter':_("Examples"),
'help':" " +
self.cmdName + " --set setup_march=x86_64:setup_formatfs=raiserfs #"+
_("modify some env") + ".\n"
},
]
self.__setParamHelp()
#Название всех сервисов
self.allServ = []
self.__setAllServ()
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'):
res = sServ.search(par['help'])
if res:
self.allServ.append(res.group(1))
def addChapterHelp(self,numChapter,helpTxt):
# Добавить в раздел помощи numChapteк тектстовую строку helpTxt
self.chapterBloc[numChapter] += helpTxt
return True
def addData(self,dataHash):
# На будущее (добавляет опции)
self.data.append(dataHash)
return True
def access(self,dataHash):
# доступна ли опция вызывающей программе
numProg = self.progName[self.cmdName]
if dataHash.has_key('progAccess'):
if numProg in dataHash['progAccess']:
return True
else:
return False
else:
return True
def __setParamHelp(self):
# записать параметры в справку
sp = []
for par in self.data:
if par.has_key("shortOption"):
if self.access(par):
sp.append(par["shortOption"])
sp.sort()
for shortOption in sp:
for par in self.data:
if par.has_key("shortOption"):
if par["shortOption"] == shortOption:
if par.has_key("optVal"):
longOption = par["longOption"] + " " +\
par["optVal"]
else:
longOption = par["longOption"]
numChapter = self.getChapterNumber(par['helpChapter'])
helpTxt = ("%%-%ds" % self.column_width) % (\
" -%s, --%s "%(par["shortOption"],longOption)) + \
par['help']+"\n"
self.addChapterHelp(numChapter,helpTxt)
break
for par in self.data:
if not par.has_key("shortOption") and \
self.access(par):
helpTxt = par['help']
numChapter = self.getChapterNumber(par['helpChapter'])
self.addChapterHelp(numChapter,helpTxt)
def getHelp(self):
# Выдать справку
help = ""
for numChapter in range(len(self.chapter)):
chapter = self.chapter[numChapter]
nameChapter = chapter[0]
visibleChapter = chapter[1]
beforeStrChapter = chapter[2]
afterStrChapter = chapter[3]
bef = ""
for i in range(beforeStrChapter):
bef += "\n"
aft = ""
for i in range(afterStrChapter):
aft += "\n"
if visibleChapter:
help += nameChapter + ": " + bef
help += self.chapterBloc[numChapter] + aft
return help
def getAllOpt(self,typeOpt="short"):
# Выдать все действующие опции
if typeOpt=="short":
if len(self.shortOpt) == 0:
for par in self.data:
if par.has_key("shortOption") and self.access(par):
if par.has_key("optVal"):
self.shortOpt.append(par["shortOption"]+':')
else:
self.shortOpt.append(par["shortOption"])
return "".join(self.shortOpt)
if typeOpt=="long":
if len(self.longOpt) == 0:
for par in self.data:
if par.has_key("longOption") and self.access(par):
if par.has_key("optVal"):
self.longOpt.append(par["longOption"]+'=')
else:
self.longOpt.append(par["longOption"])
return self.longOpt
def getShortOpt(self,option):
# Из любой опции получаем короткую опцию
for par in self.data:
if par.has_key("shortOption") and self.access(par):
if par["longOption"] == option or \
par["shortOption"] == option:
return par["shortOption"]
break
return ""
def getRunService(self, nameService):
"""Проверка, запущен ли сервис с данным именем"""
baseDir = "/var/run"
addDirDict = {"ldap":"openldap",
"samba":"samba"}
pidDir = baseDir + "/" + addDirDict[nameService]
if os.access(pidDir, os.F_OK) and os.listdir(pidDir):
return True
else:
return False
def createLdif(self, ldifFile, objVars):
"""Cоздает ldif из ldif - профиля"""
if not os.access(ldifFile, os.F_OK):
self.setError(_("Not found file:")) + "\n " + ldifFile
return False
FD = open (ldifFile)
ldifProfile = FD.read()
FD.close()
clProf = cl_profile.profile(objVars)
# Применяем условия к профилю
ldifProfile = clProf.applyTermsProfile(ldifProfile,ldifFile)
# Заменяем переменные
ldifProfile = clProf.applyVarsProfile(ldifProfile)
return ldifProfile
def execProg(self, cmdStrProg):
"""Выполняет внешнюю программу
результат строка которую выведет внешняя программа
"""
fout, fin = popen2.popen2(cmdStrProg)
fin.close()
textLine = fout.readline()
fout.read()
fout.close()
return textLine
def printRight(self, offsetLeft, offsetRight):
"""Добавляет необходимое количество пробелов:
количество пробелов = (ширина консоли - offsetLeft - offsetRight)
"""
s = struct.pack("HHHH", 0, 0, 0, 0)
fd_stdout = sys.stdout.fileno()
x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s)
#(rows, cols, x pixels, y pixels)
cols = struct.unpack("HHHH", x)[1]
for i in range(cols - offsetLeft - offsetRight):
sys.stdout.write(" ")
def colorPrint(self,attr,fg,bg,string):
"""Раскрашивает выводимое сообщение
Параметры:
attr - это атрибут
fg - цвет символа
bg - цвет фона
в случае если параметр равен "" то он не изменяется
attr может принимать следующие значения:
0 сбросить все атрибуты (вернуться в нормальный режим)
1 яркий (обычно включает толстый шрифт)
2 тусклый
3 подчёркнутый
5 мигающий
7 реверсный
8 невидимый
fg может принимать следующие значения:
30 чёрный
31 красный
32 зелёный
33 жёлтый
34 синий
35 фиолетовый
36 голубой
37 белый
bg может принимать следующие значения:
40 чёрный
41 красный
42 зелёный
43 жёлтый
44 синий
45 фиолетовый
46 голубой
47 белый
"""
lst = []
if attr:
lst.append(attr)
if fg:
lst.append(fg)
if bg:
lst.append(bg)
sys.stdout.write("\033[%sm%s\033[0m" %(";".join(lst),string))
def redBrightPrint(self, string):
"""Печатает яркое красное сообщение"""
self.colorPrint("1","31","",string)
def greenBrightPrint(self, string):
"""Печатает яркое зеленое сообщение"""
self.colorPrint("1","32","",string)
def yellowBrightPrint(self, string):
"""Печатает яркое желтое сообщение"""
self.colorPrint("1","33","",string)
def blueBrightPrint(self, string):
"""Печатает яркое cинее сообщение"""
self.colorPrint("1","34","",string)
def lenString(self, string):
"""Получаем длинну строки"""
stringUnicode = self._toUNICODE(string)
lenString = len(stringUnicode)
return lenString
def defaultPrint(self, string):
sys.stdout.write(string)
sys.stdout.flush()
def printLine(self, argL, argR):
"""Печатает справа и слева консоли цветные сообщения"""
#Допустимые цвета
colorDict = {\
# цвет по умолчанию
'':self.defaultPrint,
# ярко зеленый
'greenBr':self.greenBrightPrint,
# ярко голубой
'blueBr':self.blueBrightPrint,
# ярко красный
'redBr':self.redBrightPrint,
# ярко желтый
'yellowBr':self.yellowBrightPrint,
}
# cмещение от левого края консоли
offsetL = 0
for color,leftString in argL:
offsetL += self.lenString(leftString)
if colorDict.has_key(color):
# печатаем и считаем смещение
colorDict[color](leftString)
else:
colorDict[''](leftString)
# cмещение от правого края консоли
offsetR = 0
for color,rightString in argR:
offsetR += self.lenString(rightString)
# Добавляем пробелы
self.printRight(offsetL, offsetR)
for color,rightString in argR:
if colorDict.has_key(color):
# печатаем и считаем смещение
colorDict[color](rightString)
else:
colorDict[''](rightString)
print ""
def printNotOK(self, string):
"""Вывод на печать в случае сбоя"""
self.printLine((('greenBr',' * '),
('',string),
),
(('blueBr','['),
('redBr',' !! '),
('blueBr',']'),
)
)
def printOK(self, string):
"""Вывод на печать в случае успеха"""
self.printLine((('greenBr',' * '),
('',string),
),
(('blueBr','['),
('greenBr',' ok '),
('blueBr',']'),
)
)
def printWARNING(self, string):
"""Вывод на печать предупреждения"""
self.printLine((('yellowBr',' * '),
('',string),
),
(('',''),
)
)
def printERROR(self, string):
"""Вывод на печать предупреждения"""
self.printLine((('redBr',' * '),
('',string),
),
(('',''),
)
)
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'] == 'all':
datavars.printVars()
# вывод параметров, используюя фильтр
else:
datavars.printVars(
[i.strip() for i in options['e'].split(':')])
return False
return True
def setupLdapServer(self, options):
"""Начальная настройка LDAP сервиса"""
# Принудительная установка
forceOptions = False
if options.has_key("f"):
forceOptions = True
clVars = cl_base.DataVars()
clVars.flServer()
clVars.flIniFile()
# прервать если была неудачная попытка установить новые параметры
# или были опция вывода на печать
if not self.processOptionsForDatavars(options,clVars):
return ""
# В случае если сервер установлен
if clVars.Get("soft_ldap_setup") == "yes" and\
not forceOptions:
self.printWARNING (_("WARNING") + ": " +\
_("LDAP server is configured")+ ".")
return True
# Проверим запущен ли ldap
if self.getRunService("ldap"):
self.printWARNING (_("WARNING") + ": " +\
_("The LDAP service is running") + ".")
print "1. " +_("Stop the LDAP service")
print " /etc/init.d/slapd stop"
print "2. " + _("You can save configuration files and a database \
LDAP in backup directory")
print "3. " + _("Restart the program")
return True
#self.setParamIniFile("setup_LDAP","no")
clVars.Write("soft_ldap_setup","no")
# Для тестовых целей устанавливаем директорию инсталяции
#clVars.Set("setup_path_install","/tmp/test1/")
# Устанавливаем переменную (говорит о том что первый проход)
clVars.Set("setup_pass_parser","1",True)
# Cоздаем объект профиль устанавливая директорию ldap для
# файлов профилей
clProf = cl_profile.profile(clVars,"ldap")
# Объединяем профили
clProf.applyProfiles()
# Удаляем предыдущую базу данных
self.execProg("rm -rf /var/lib/openldap-data/*")
self.printOK(_("Remove previons LDAP Database ..."))
# Запускаем LDAP сервер
textLine = self.execProg("/etc/init.d/slapd start")
ldifFile = "/usr/lib/calculate/calculate-server/ldif/ldap_base.ldif"
if "ok" in textLine:
self.printOK(_("LDAP start ..."))
else:
self.printNotOK(_("LDAP start ..."))
return False
baseLdif = self.createLdif(ldifFile, clVars)
#print baseLdif
#clVars.printVars()
ldapObj = ldapFunction(clVars.Get("soft_ldap_admin_tmp"),
clVars.Get("soft_ldap_adminpw_tmp"))
if not ldapObj.getError():
ldapObj.ldapAdd(baseLdif)
if ldapObj.getError():
print _("LDAP Error") + ": " + ldapObj.getError()
return False
self.printOK(_("Add ldif file ..."))
# Удаляем временного пользователя root из конфигурационного файла
clVars.Set("setup_pass_parser","2",True)
clProf.applyProfiles()
# Перезапускаем LDAP сервер
textLine = self.execProg("/etc/init.d/slapd restart")
if "ok" in textLine:
self.printOK(_("LDAP configure and restart ..."))
else:
self.printNotOK(_("LDAP configure and restart ..."))
return False
ldapParser = iniLdapParser()
ldapParser.setVar("admin",
{"DN":clVars.Get("soft_ldap_admin"),
"PASS":clVars.Get("soft_ldap_adminpw")})
clVars.Write("soft_ldap_setup","yes")
return True
def setupSambaServer(self, options):
"""Начальная настройка Samba сервиса"""
# Принудительная установка
forceOptions = False
if options.has_key("f"):
forceOptions = True
clVars = cl_base.DataVars()
clVars.flServer()
clVars.flIniFile()
# прервать если была неудачная попытка установить новые параметры
# или были опция вывода на печать
if not self.processOptionsForDatavars(options,clVars):
return ""
# В случае если сервер установлен
if clVars.Get("soft_samba_setup") == "yes" and\
not forceOptions:
self.printWARNING (_("WARNING") + ": " +\
_("Samba server is configured")+ ".")
return True
# Проверим запущен ли сервис Samba
if self.getRunService("samba"):
self.printWARNING (_("WARNING") + ": " +\
_("The Samba service is running") + ".")
print "1. " +_("Stop the Samba service")
print " /etc/init.d/samba stop"
print "2. " + _("You can save configuration files \
Samba in backup directory")
print "3. " + _("Restart the program")
return True
clVars.Write("soft_samba_setup","no")
# Cоздаем объект профиль устанавливая директорию samba для
# файлов профилей
clProf = cl_profile.profile(clVars,"samba")
# Объединяем профили
clProf.applyProfiles()
ldapParser = iniLdapParser()
pswd = ldapParser.getVar("admin","PASS")
if not pswd:
self.printERROR(_("ERROR") + ": " +\
_("Not find Ldap admin password"))
return False
textLine = self.execProg("smbpasswd -w %s" %(pswd))
if not "stored" in textLine:
self.printERROR(_("ERROR") + ": " +\
_("Add Ldap admin password"))
return False
textLine = self.execProg("/etc/init.d/slapd restart")
if not "ok" in textLine:
self.printNotOK(_("LDAP restart ..."))
return False
textLine = self.execProg("/etc/init.d/samba start")
if "ok" in textLine:
self.printOK(_("Samba start ..."))
else:
self.printNotOK(_("Samba start ..."))
return False
clVars.Write("soft_samba_setup","yes")
self.printOK(_("Samba service configured ..."))
return True
def addUserLdapServer(self, options):
"""Добавляет LDAP пользователя в LDAP-сервер"""
clVars = cl_base.DataVars()
clVars.flServer()
clVars.flIniFile()
# прервать если была неудачная попытка установить новые параметры
# или были опция вывода на печать
if not self.processOptionsForDatavars(options,clVars):
return ""