#-*- 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