#-*- 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 re import sys import cl_base import cl_profile import cl_utils2 import cl_utils import ldap Version = "calculate-client 0.0.1" 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, 'cl-createhome':1 } # 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") }, { 'progAccess':(1,), 'helpChapter':_("Usage"), 'help': cmdName + " " + _("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':"m", 'longOption':"create-home", 'helpChapter':_("Common options"), 'help':_("create home directory for the new user account") }, {'progAccess':(1,), 'longOption':"vars", 'optVal':_("TYPE_VAR"), 'helpChapter':_("Common options"), 'help':_("print variables (TYPE_VAR - all:full var)") }, {'progAccess':(0,), 'shortOption':"s", 'longOption':"cl-server", 'optVal':_("CL_SERVER"), 'helpChapter':_("Common options"), 'help':_("name or ip calculate server") }, {'progAccess':(0,), 'shortOption':"p", 'longOption':"prvar", 'optVal':_("TYPES_VAR"), 'helpChapter':_("Common options"), 'help':_("print variable (filter type - comma delimited)") }, ] 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) # Имя пользователя userName = os.environ['USER'] self.userName = userName.lower() # Объект хранения переменных self.clVars = False 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("ld_base_dn") 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("ld_bind_dn") bindPw = self.clVars.Get("ld_bind_pw") 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 "" def searchLineInFile(self, name, fileName, numEl=0): """Ищет строку в которой есть название разделенное ':' в файле похожем на /etc/passwd""" if os.path.exists(fileName): FD = open(fileName) lines = FD.readlines() FD.close() lineFound = "" for line in lines: if name == line.split(":")[numEl]: lineFound = line break if lineFound: return lineFound else: return False def searchPasswdUser(self, userName): """Ищет пользователей в /etc/passwd""" filePasswd = "/etc/passwd" return self.searchLineInFile(userName, filePasswd) def getUserUidGid(self, userName): """Выдаем uid и gid пользователя""" 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('uidNumber') and\ searchUser[0][0][1].has_key('gidNumber'): return (searchUser[0][0][1]['uidNumber'][0], searchUser[0][0][1]['gidNumber'][0]) else: return () def createUserDir(self, uid, gid, userDir, mode=0700): """Создание пользовательской директории""" if not os.path.exists(userDir): os.makedirs(userDir) if mode: os.chmod(userDir,mode) os.chown(userDir,uid,gid) return True else: self.printERROR(_("Path %s exists") %userDir) return False def applyProfilesFromUser(self): """Применяем профили для пользователя""" # Cоздаем объект профиль clProf = cl_profile.profile(self.clVars) # Объединяем профили clProf.applyProfiles() if clProf.getError(): self.printERROR(clProf.getError()) return False else: return True def chownR(self, directory, uid, gid): """изменяет владельца и группу для всех файлов и директорий внутри directory """ fileObj = cl_profile._file() scanObjs = fileObj.scanDirs([directory]) # меняем владельца домашней директории os.chown(directory, uid,gid) # Меняем владельца директорий for dirCh in scanObjs[0].dirs: os.chown(dirCh, uid,gid) # Меняем владельца файлов for fileCh in scanObjs[0].files: os.chown(fileCh, uid,gid) # Меняем владельца ссылок for linkCh in scanObjs[0].links: os.lchown(linkCh[1], uid, gid) return True def execProg(self, cmdStrProg, inStr=False, retFull=True): """Выполняет внешнюю программу Параметры: cmdStrProg внешняя программа inStr данные передаваемые программе на страндартный вход. Возвращаемые параметры: строка которую выведет внешняя программа """ return cl_utils.runOsCommand(cmdStrProg, inStr, retFull) #def getUidAndGidUser(self, userName): #strRes = self.execProg("id %s" %userName) #reFind = re.compile("uid=(\d+)\(.+gid=(\d+)\(") #res = reFind.search(strRes) #if res: #return res.group(1), res.group(2) #else: #self.printERROR(_("User %s not found")\ #%str(userName)) #return False def getUidAndGidUser(self, userName): """получаем uid и gid пользователя из /etc/passwd""" resPasswd = self.searchPasswdUser(userName) if resPasswd: uid = resPasswd.split(":")[2] gid = resPasswd.split(":")[3] full_name = resPasswd.split(":")[4] return (uid, gid, full_name) else: return False def createHome(self, userName=False): # Подсоединяемся к movie #if not self.getLdapObjBind(server): #return False # Создаем объект переменных self.createClVars() if userName: self.userName = userName #uidGid = self.getUserUidGid(self.userName) uidGid = self.getUidAndGidUser(self.userName) if not uidGid: self.printERROR(_(" Not found user uid and gid")) return False uid = int(uidGid[0]) gid = int(uidGid[1]) fullName = uidGid[2] # Создаем пользовательскую директорию homeDir = os.path.join("/home",self.userName) self.clVars.Set('cl_root_path',homeDir,True) if not os.path.exists(homeDir): self.createUserDir(uid, gid, homeDir) # Записываем переменную логин self.clVars.Set('ur_login',self.userName) self.clVars.Set('ur_fullname',fullName) # Применяем профили для пользователя if not self.applyProfilesFromUser(): self.printERROR(_(" Not apply user profile")) return False self.chownR(homeDir, uid, gid) self.printSUCCESS(_("created home dir %s")%homeDir) return True 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() # В случае остсутствия опций командной строки и имени пользователя if notOptError and not self.opt and not 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