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.
 
 
 
 
 
 

358 lines
15 KiB

#-*- 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 re
import sys
import cl_base
import cl_profile
import cl_utils2
import cl_utils
import ldap
Version = "calculate-client 0.0.1_alpha"
tr = cl_base.lang()
tr.setLanguage(sys.modules[__name__])
pcs = cl_utils.prettyColumnStr
# Импортированные классы в 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 cl_client(imp_cl_err, imp_cl_xml, imp_cl_help, imp_cl_smcon):
"""Основной класс для работы с LDAP"""
def __init__(self, cmdName):
# объект для форматированного вывода
imp_cl_help.__init__(self, cmdName)
servName = ""
if "user" in cmdName:
servName = _("user")
self.chapter = [\
# расположение разделов на странице
# имя раздела, видимый или невидимый, кол. "\n" после
# названия раздела, кол. "\n" после раздела
# тип раздела
("Copyright",False,0,2,""),
(_("Usage"),True,0,1,""),
("Function",False,0,2,""),
(_("Examples"),True,1,1,""),
(_("Common options"),True,1,0,"options"),
]
# имена используемых программ и их номера для доступа к переменным
# self.data
self.progName = { 'cl-client':0,
}
# Cвязь длинных опций помощи и выводимых разделов помощи с опциями
self.relOptions = {"h":[_("Common 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 = [\
{
#Copyright
#'progAccess':(3,),
'helpChapter':"Copyright",
'help':Version
},
#Usage
{
'progAccess':(0,),
'helpChapter':_("Usage"),
'help': cmdName + " [" + _("options") + "] " + _("user")
},
# Function
{
'progAccess':(0,),
'helpChapter':"Function",
'help':_("Client for the calculate-server")
},
# Examples
{
'progAccess':(0,),
'helpChapter':_("Examples"),
'help':pcs( " cl-client -m test", self.column_width,
"# " + _("mounts a test user directory on the server \
calculate-server"),
self.consolewidth-self.column_width )
},
# Options
{'shortOption':"h",
'longOption':"help",
'helpChapter':_("Common options"),
'help':_("display this help and exit")
},
{'progAccess':(0,),
'shortOption':"f",
'longOption':"force",
'helpChapter':_("Common options"),
'help':_("force exit with success status") + " " +\
_("if the specified group already exists")
},
]
self._cl_help__setParamHelp()
# Удаляем ненужный аттрибут класса cl_profile.xmlShare
self._createElement = False
delattr(self, "_createElement")
# Переменная объект Vars
self.clVars = False
# Переменная объект ldapFunction
self.ldapObj = False
# Переменная соединение с LDAP сервером
self.conLdap = False
# Базовый DN LDAP сервера
self.baseDN = False
# DN сервисов относительно базового
self.ServicesDN = "ou=Services"
self.relUsDN = 'ou=Users'
self.relServDN = 'ou=Unix'
self.relDN = self.addDN(self.relServDN,self.ServicesDN)
# DN пользователей, относительно базового DN
self.relUsersDN = self.addDN(self.relUsDN, self.relDN)
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 createClVars(self, clVars=False):
"""Создает объект Vars"""
if not clVars:
clVars = cl_base.DataVars()
clVars.flClient()
#clVars.flIniFile()
# Устанавливаем у объекта объект Vars
self.clVars = clVars
return True
def addDN(self, *arg):
"""Складывает текстовые элементы DN"""
DNs = []
for dn in arg:
if dn:
DNs.append(dn)
return ','.join(DNs)
def searchLdapDN(self, name, relDN, attr, retAttr=None):
"""Находит DN в LDAP"""
baseDN = self.clVars.Get("soft_ldap_base")
DN = self.addDN(relDN,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
def searchUnixUser(self, userName):
"""Находит пользователя сервиса Unix"""
resSearch = self.searchLdapDN(userName, self.relUsersDN, "uid")
return resSearch
def getLdapObjBind(self, host):
"""Получаем объект ldapFunction
Соединяемся пользователем bind
В выходном объекте есть соединение с LDAP сервером: self.conLdap
"""
self.createClVars(self.clVars)
bindDn = self.clVars.Get("soft_ldap_bind")
bindPw = self.clVars.Get("soft_ldap_bindpw")
if not (bindDn or bindPw):
self.printERROR(_("not found LDAP bind DN or password") + " ...")
return False
ldapObj = cl_utils2.ldapFun(bindDn, bindPw, host)
if ldapObj.getError():
self.printERROR (_("LDAP connect error") + ": " +\
ldapObj.getError().strip())
return False
# Устанавливаем у объекта соединение и объект LDAP функций
self.ldapObj = ldapObj
self.conLdap = ldapObj.conLdap
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 ""
class tsOpt(cl_base.opt):
"""Класс для обработки параметров и вывода help
Параметры:
helpObj объект-справка содержащий необходимые опции
notOptError выдавать ошибку при отсутствии опций командной строки
"""
def __init__(self, helpObj, notOptError=False):
# от cl_help получаем короткие и длинные опции
shortOpt,longOpt = helpObj.getAllOpt('all', helpObj.relOptions['h'])
# вызвать конструктор объекта, распознающего опции
cl_base.opt.__init__(self,shortOpt,longOpt)
self.nameParams = ['user']
self.sysArgv = sys.argv[1:]
self.helpObj = helpObj
self.__iter = 0
self.opt = {}
self.params = {}
self.getopt()
# Обработка help
self.flagHelp = 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:
print helpObj.getHelp(helpObj.relOptions['h'])
self.flagHelp = True
else:
if self.params.has_key('user'):
if len(self.nameParams) != self.__iter:
self.handlerErrOpt()
else:
self.handlerErrOpt()
# В случае остсутствия опций командной строки
if notOptError and not self.opt and self.params.has_key('user'):
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):
# Обработчик ошибок
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