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-client/pym/cl_client.py

429 lines
16 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 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':(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 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 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])
# Создаем пользовательскую директорию
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_name',self.userName)
# Применяем профили для пользователя
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()
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