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

  1. #-*- coding: utf-8 -*-
  2. #Copyright 2008 Calculate Pack, http://www.calculate-linux.ru
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import re
  16. import sys
  17. import cl_base
  18. import cl_profile
  19. import cl_utils2
  20. import cl_utils
  21. import ldap
  22. Version = "calculate-client 0.0.1_alpha"
  23. tr = cl_base.lang()
  24. tr.setLanguage(sys.modules[__name__])
  25. pcs = cl_utils.prettyColumnStr
  26. # Импортированные классы в cl_ldap
  27. # Запись ошибок
  28. imp_cl_err = cl_profile._error
  29. # Работа с XML
  30. imp_cl_xml = cl_profile.xmlShare
  31. # Обработка параметров командной строки
  32. imp_cl_help = cl_utils2.cl_help
  33. # Форматированный вывод
  34. imp_cl_smcon = cl_utils2.cl_smartcon
  35. class cl_client(imp_cl_err, imp_cl_xml, imp_cl_help, imp_cl_smcon):
  36. """Основной класс для работы с LDAP"""
  37. def __init__(self, cmdName):
  38. # объект для форматированного вывода
  39. imp_cl_help.__init__(self, cmdName)
  40. servName = ""
  41. if "user" in cmdName:
  42. servName = _("user")
  43. self.chapter = [\
  44. # расположение разделов на странице
  45. # имя раздела, видимый или невидимый, кол. "\n" после
  46. # названия раздела, кол. "\n" после раздела
  47. # тип раздела
  48. ("Copyright",False,0,2,""),
  49. (_("Usage"),True,0,1,""),
  50. ("Function",False,0,2,""),
  51. (_("Examples"),True,1,1,""),
  52. (_("Common options"),True,1,0,"options"),
  53. ]
  54. # имена используемых программ и их номера для доступа к переменным
  55. # self.data
  56. self.progName = { 'cl-client':0,
  57. }
  58. # Cвязь длинных опций помощи и выводимых разделов помощи с опциями
  59. self.relOptions = {"h":[_("Common options")],}
  60. # список разделов, которые на наличие в ней информации
  61. # используется для автоматического отображения/скрытия
  62. # опций help-имя
  63. # Пример: self.relOption =
  64. # { "help-all":[_("Common options"], _("Unix service options"),
  65. # _("Samba service options"), _("LDAP service options")}]
  66. # self.relChapterPass = (_("Common options"),)
  67. # это означается что опция будет активна, если только в разделах
  68. # кроме Common options есть хоть одна доступная опция.
  69. self.relChapterPass = (_("Common options"),)
  70. self.data = [\
  71. {
  72. #Copyright
  73. #'progAccess':(3,),
  74. 'helpChapter':"Copyright",
  75. 'help':Version
  76. },
  77. #Usage
  78. {
  79. 'progAccess':(0,),
  80. 'helpChapter':_("Usage"),
  81. 'help': cmdName + " [" + _("options") + "] " + _("user")
  82. },
  83. # Function
  84. {
  85. 'progAccess':(0,),
  86. 'helpChapter':"Function",
  87. 'help':_("Client for the calculate-server")
  88. },
  89. # Examples
  90. {
  91. 'progAccess':(0,),
  92. 'helpChapter':_("Examples"),
  93. 'help':pcs( " cl-client -m test", self.column_width,
  94. "# " + _("mounts a test user directory on the server \
  95. calculate-server"),
  96. self.consolewidth-self.column_width )
  97. },
  98. # Options
  99. {'shortOption':"h",
  100. 'longOption':"help",
  101. 'helpChapter':_("Common options"),
  102. 'help':_("display this help and exit")
  103. },
  104. {'progAccess':(0,),
  105. 'shortOption':"f",
  106. 'longOption':"force",
  107. 'helpChapter':_("Common options"),
  108. 'help':_("force exit with success status") + " " +\
  109. _("if the specified group already exists")
  110. },
  111. ]
  112. self._cl_help__setParamHelp()
  113. # Удаляем ненужный аттрибут класса cl_profile.xmlShare
  114. self._createElement = False
  115. delattr(self, "_createElement")
  116. # Переменная объект Vars
  117. self.clVars = False
  118. # Переменная объект ldapFunction
  119. self.ldapObj = False
  120. # Переменная соединение с LDAP сервером
  121. self.conLdap = False
  122. # Базовый DN LDAP сервера
  123. self.baseDN = False
  124. # DN сервисов относительно базового
  125. self.ServicesDN = "ou=Services"
  126. self.relUsDN = 'ou=Users'
  127. self.relServDN = 'ou=Unix'
  128. self.relDN = self.addDN(self.relServDN,self.ServicesDN)
  129. # DN пользователей, относительно базового DN
  130. self.relUsersDN = self.addDN(self.relUsDN, self.relDN)
  131. def processOptionsForDatavars(self, options, datavars):
  132. '''Обработать опции связанные с переменными окружения
  133. Параметры:
  134. options словарь опций ( <буква опции>:<значение>
  135. обрабатывает буквы 's' для установки параметров
  136. 'e' для отображения)
  137. datavars объект-хранилище переменных окружнения
  138. Возвращаемые значения:
  139. True удалось установить указанные параметры
  140. False метод вызван для просмотра переменных окружения, или
  141. установка переменных окружения прошла с ошибками.
  142. '''
  143. # если это установка параметров
  144. if 's' in options:
  145. # если установки параметрв не произошло
  146. if not datavars.flFromCmdParam(options['s']):
  147. # вывод
  148. print _("Bad enviroment parameters")
  149. return False
  150. # если опция отображения параметров
  151. if 'e' in options:
  152. # вывод всех параметров
  153. if options['e'] == '*':
  154. datavars.printVars()
  155. # вывод параметров, используюя фильтр
  156. else:
  157. datavars.printVars(
  158. [i.strip() for i in options['e'].split(':')])
  159. return False
  160. return True
  161. def handleCheckAccess(self,dataHash):
  162. """Дополнительная проверка опций-справок - опция доступна только если
  163. в разделах этой справки есть хотябы одна опция
  164. Входные параметры:
  165. dataHash словарь из списка self.data
  166. """
  167. # если эта опция для реализации справки
  168. if 'longOption' in dataHash \
  169. and dataHash['longOption'] in self.relOptions:
  170. # составляем список разделов которые должны быть не пустые
  171. # разделы из relOptions относящиеся к этой опции за исключением
  172. # разделов которые надо пропустить (relChapterPass)
  173. trueChapters = \
  174. set(self.relOptions[dataHash['longOption']]).difference( \
  175. self.relChapterPass)
  176. # перебираем все опции
  177. for unit in self.data:
  178. # если опция не отностится к выполняемой программе, то
  179. # ее пропустить
  180. if 'progAccess' in unit and \
  181. not self.progName[self.cmdName] in unit['progAccess']:
  182. continue
  183. # если опция отностится к необходмой справки
  184. if unit['helpChapter'] in trueChapters:
  185. # опция справки - доступна
  186. return True
  187. # если не оказалось не одной опция для разделов этой справки
  188. return False
  189. # опция доступна, так как не справочная
  190. return True
  191. def createClVars(self, clVars=False):
  192. """Создает объект Vars"""
  193. if not clVars:
  194. clVars = cl_base.DataVars()
  195. clVars.flClient()
  196. #clVars.flIniFile()
  197. # Устанавливаем у объекта объект Vars
  198. self.clVars = clVars
  199. return True
  200. def addDN(self, *arg):
  201. """Складывает текстовые элементы DN"""
  202. DNs = []
  203. for dn in arg:
  204. if dn:
  205. DNs.append(dn)
  206. return ','.join(DNs)
  207. def searchLdapDN(self, name, relDN, attr, retAttr=None):
  208. """Находит DN в LDAP"""
  209. baseDN = self.clVars.Get("soft_ldap_base")
  210. DN = self.addDN(relDN,baseDN)
  211. #searchScope = ldap.SCOPE_SUBTREE
  212. searchScope = ldap.SCOPE_ONELEVEL
  213. searchFilter = "%s=%s" %(attr,name)
  214. retrieveAttributes = retAttr
  215. resSearch = self.ldapObj.ldapSearch(DN, searchScope,
  216. searchFilter, retrieveAttributes)
  217. return resSearch
  218. def searchUnixUser(self, userName):
  219. """Находит пользователя сервиса Unix"""
  220. resSearch = self.searchLdapDN(userName, self.relUsersDN, "uid")
  221. return resSearch
  222. def getLdapObjBind(self, host):
  223. """Получаем объект ldapFunction
  224. Соединяемся пользователем bind
  225. В выходном объекте есть соединение с LDAP сервером: self.conLdap
  226. """
  227. self.createClVars(self.clVars)
  228. bindDn = self.clVars.Get("soft_ldap_bind")
  229. bindPw = self.clVars.Get("soft_ldap_bindpw")
  230. if not (bindDn or bindPw):
  231. self.printERROR(_("not found LDAP bind DN or password") + " ...")
  232. return False
  233. ldapObj = cl_utils2.ldapFun(bindDn, bindPw, host)
  234. if ldapObj.getError():
  235. self.printERROR (_("LDAP connect error") + ": " +\
  236. ldapObj.getError().strip())
  237. return False
  238. # Устанавливаем у объекта соединение и объект LDAP функций
  239. self.ldapObj = ldapObj
  240. self.conLdap = ldapObj.conLdap
  241. return True
  242. def getUserMail(self, userName):
  243. """Выдаем основной почтовый адрес"""
  244. searchUser = self.searchUnixUser(userName)
  245. if not searchUser:
  246. self.printERROR(_("User %s not found in Unix service")\
  247. %str(userName))
  248. return False
  249. if searchUser[0][0][1].has_key('mail'):
  250. return searchUser[0][0][1]['mail'][0]
  251. else:
  252. return ""
  253. class tsOpt(cl_base.opt):
  254. """Класс для обработки параметров и вывода help
  255. Параметры:
  256. helpObj объект-справка содержащий необходимые опции
  257. notOptError выдавать ошибку при отсутствии опций командной строки
  258. """
  259. def __init__(self, helpObj, notOptError=False):
  260. # от cl_help получаем короткие и длинные опции
  261. shortOpt,longOpt = helpObj.getAllOpt('all', helpObj.relOptions['h'])
  262. # вызвать конструктор объекта, распознающего опции
  263. cl_base.opt.__init__(self,shortOpt,longOpt)
  264. self.nameParams = ['user']
  265. self.sysArgv = sys.argv[1:]
  266. self.helpObj = helpObj
  267. self.__iter = 0
  268. self.opt = {}
  269. self.params = {}
  270. self.getopt()
  271. # Обработка help
  272. self.flagHelp = False
  273. # определяем есть ли среди опций опции, которые влияют на показ
  274. # опциональных разделов (метод пересечения множеств)
  275. helpopt = \
  276. tuple(set(self.opt.keys()).intersection(helpObj.relOptions.keys()))
  277. #Если есть опции help
  278. if len(helpopt) > 0:
  279. print helpObj.getHelp(helpObj.relOptions[helpopt[0]])
  280. self.flagHelp = True
  281. #Если нет хвостов
  282. elif not self.params:
  283. print helpObj.getHelp(helpObj.relOptions['h'])
  284. self.flagHelp = True
  285. else:
  286. if self.params.has_key('user'):
  287. if len(self.nameParams) != self.__iter:
  288. self.handlerErrOpt()
  289. else:
  290. self.handlerErrOpt()
  291. # В случае остсутствия опций командной строки
  292. if notOptError and not self.opt and self.params.has_key('user'):
  293. self.printErrorNotOpt()
  294. self.flagHelp = True
  295. def printErrorNotOpt(self):
  296. """Сообщение в случае отсутствия опций"""
  297. print _("Options are absent.")
  298. def handlerOpt(self,option,value):
  299. # Обработчик (опция значение)
  300. #print option, value
  301. shortOpt = self.helpObj.getShortOpt(option)
  302. if not shortOpt:
  303. shortOpt = option
  304. if not shortOpt in self.opt:
  305. self.opt[shortOpt] = value
  306. def handlerErrOpt(self):
  307. # Обработчик ошибок
  308. argv = " ".join(sys.argv[1:])
  309. print _("Unrecognized option") + ' "' + argv + '"\n' + \
  310. _("Try") + ' "' + sys.argv[0].split("/")[-1] + ' --help" ' +\
  311. _("for more information.")
  312. def handlerParam(self,param):
  313. # Обработчик хвостов (значение)
  314. self.__iter += 1
  315. if self.__iter<=len(self.nameParams):
  316. self.params[self.nameParams[self.__iter-1]] = param