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

1062 lines
43 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
import types
import getpass
import _cl_keys
Version = "calculate-client 0.0.6"
tr = cl_base.lang()
tr.setLanguage(sys.modules[__name__])
pcs = cl_utils.prettyColumnStr
class printNoColor:
def colorPrint(self,attr,fg,bg,string):
sys.stdout.write(string)
# Импортированные классы в 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):
"""Основной класс для работы клиентских приложений"""
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,
'cl-sync':2
}
# 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") + "] " + _("domain")
},
{
'progAccess':(1,),
'helpChapter':_("Usage"),
'help': cmdName + " " + _("user")
},
{
'progAccess':(2,),
'helpChapter':_("Usage"),
'help': cmdName + " [" + _("options") + "] " + _("user")
},
# Function
{
'progAccess':(0,),
'helpChapter':"Function",
'help':_("Changes settings for connecting to domain \
(calculate-server)")
},
{
'progAccess':(1,),
'helpChapter':"Function",
'help':_("Create home directory for the new user account")
},
{
'progAccess':(2,),
'helpChapter':"Function",
'help':_("Mounting directories and synchronize the user preferences")
},
# Examples
{
'progAccess':(0,),
'helpChapter':_("Examples"),
'help':pcs( " cl-client 192.168.0.1", self.column_width,
"# " + _("Adds settings for connecting to domain \
(ip 192.168.0.1)"),
self.consolewidth-self.column_width )
},
# Options
{'shortOption':"h",
'longOption':"help",
'helpChapter':_("Common options"),
'help':_("display this help and exit")
},
{'progAccess':(0,),
'shortOption':"r",
'helpChapter':_("Common options"),
'help':_("Removes the settings for connecting to a domain")
},
{'progAccess':(0,1,2),
'longOption':"vars",
'optVal':_("TYPE_VAR"),
'helpChapter':_("Common options"),
'help':_("print variables (TYPE_VAR - all:full var)")
},
{'progAccess':(0,1,2),
'longOption':"color",
'optVal':_("WHEN"),
'helpChapter':_("Common options"),
'help':_("control whether color is used to distinguish file types. \
WHEN may be 'never', 'always', or 'auto'")
},
{'progAccess':(1,),
'shortOption':"f",
'longOption':"force",
'helpChapter':_("Common options"),
'help':_("always join the user profiles and preferences")
},
{'progAccess':(0,),
'longOption':"mount",
'helpChapter':_("Common options"),
'help':_("mount [remote] resource for Samba (calculate-server)")
},
{'progAccess':(2,),
'longOption':"login",
'helpChapter':_("Common options"),
'help':_("mount user resource")+ " " +\
_("and synchronize the user preferences")
},
{'progAccess':(2,),
'longOption':"logout",
'helpChapter':_("Common options"),
'help':_("synchronize the user preferences") + " " +\
_("and umount user resource")
},
{'progAccess':(2,),
'longOption':"nosync",
'helpChapter':_("Common options"),
'help':_("not synchronize the user preferences, is used in \
conjunction with the 'login' or 'logout'")
},
#{'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.relGrDN = 'ou=Groups'
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)
# DN групп, относительно базового DN
self.relGroupsDN = self.addDN(self.relGrDN, self.relDN)
# Объект хранения переменных
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 searchUnixGid(self, groupId):
"""Находит группу сервиса Unix по ёе id"""
resSearch = self.searchLdapDN(str(groupId), self.relGroupsDN,
"gidNumber")
return resSearch
def getLdapObjBind(self, host, printError=True):
"""Получаем объект 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):
if printError:
self.printERROR(_("Not found LDAP bind DN or password") +\
" ...")
return False
ldapObj = cl_utils2.ldapFun(bindDn, bindPw, host)
if ldapObj.getError():
if printError:
self.printERROR (_("LDAP connect error") + ": " +\
ldapObj.getError().strip())
return False
# Устанавливаем у объекта соединение и объект LDAP функций
self.ldapObj = ldapObj
self.conLdap = ldapObj.conLdap
return True
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 searchGroupGid(self, groupId):
"""Ищет gid в /etc/group"""
gid = str(groupId)
fileGroup = "/etc/group"
return self.searchLineInFile(gid, fileGroup, 2)
def getUserLdapInfo(self, userName, printError=True):
"""Выдаем uid и gid пользователя"""
searchUser = self.searchUnixUser(userName)
if not searchUser:
if printError:
self.printERROR(_("User %s not found in Unix service")\
%str(userName))
return False
uid = False
gid = False
fullName = ""
mail = ""
if searchUser[0][0][1].has_key('uidNumber'):
uid = searchUser[0][0][1]['uidNumber'][0]
if searchUser[0][0][1].has_key('gidNumber'):
gid = searchUser[0][0][1]['gidNumber'][0]
searchGroup = self.searchUnixGid(gid)
if searchGroup and searchGroup[0][0][1].has_key('cn'):
group = searchGroup[0][0][1]['cn'][0]
if searchUser[0][0][1].has_key('cn'):
fullName = searchUser[0][0][1]['cn'][0]
if searchUser[0][0][1].has_key('mail'):
mail = searchUser[0][0][1]['mail'][0]
if searchUser[0][0][1].has_key('homeDirectory'):
home = searchUser[0][0][1]['homeDirectory'][0]
if uid and gid:
return (uid, gid, fullName, mail, home, group)
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)
# Объединяем профили
dirsFiles = clProf.applyProfiles()
if clProf.getError():
self.printERROR(clProf.getError())
return False
else:
return dirsFiles
def getUserPassword(self, pwDialog=False):
"""Получить пароль у пользователя
pwDialog - приглашение ввода пароля
"""
if not pwDialog:
pwDialog = _("Password")
userPwd = getpass.getpass(pwDialog+":")
userPwd = re.sub("(\W)", r"\\\1",userPwd)
return userPwd
def chownR(self, directory, uid, gid, dirsAndFiles=False):
"""изменяет владельца и группу
для всех файлов и директорий внутри directory
"""
if dirsAndFiles:
dirs, files = dirsAndFiles
# меняем владельца домашней директории
os.chown(directory, uid,gid)
# Меняем владельца директорий
for dirCh in dirs:
if os.path.exists(dirCh):
os.chown(dirCh, uid,gid)
# Меняем владельца файлов
for fileCh in files:
if os.path.exists(fileCh):
if os.path.islink(fileCh):
os.lchown(fileCh, uid, gid)
else:
os.chown(fileCh, uid,gid)
return True
else:
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 getUserPasswdInfo(self, userName):
"""получаем uid и gid пользователя из /etc/passwd"""
resPasswd = self.searchPasswdUser(userName)
if resPasswd:
uid = resPasswd.split(":")[2]
gid = resPasswd.split(":")[3]
fullName = resPasswd.split(":")[4]
mail = ""
group = ""
home = os.path.join("/home",userName)
resGroup = self.searchGroupGid(gid)
if resGroup:
group = resGroup.split(":")[0]
return (uid, gid, fullName, mail, home, group)
else:
return False
def getAlwaysProfilePath(self):
"""Получаем пути к профилям которые применяются постоянно"""
profilePath = self.clVars.Get('cl_profile_path')
alwProfilePath = []
for prPath in profilePath:
if os.path.split(prPath)[1] == "always":
alwProfilePath.append(prPath)
return alwProfilePath
def createHome(self, userName, applyAlways=False):
"""Создание пользовательской директории с настройками для kde4"""
# Создаем объект переменных
self.createClVars()
uidGid = False
# Подсоединяемся к серверу
domain = self.clVars.Get("cl_remote_host")
connectLdap = False
if domain:
if not self.getLdapObjBind(domain):
return False
connectLdap = True
if connectLdap:
# uid и gid и mail из Ldap
uidGid = self.getUserLdapInfo(userName,False)
if not domain:
# uid и gid и mail из passwd
uidGid = self.getUserPasswdInfo(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]
mail = uidGid[3]
homeDir = uidGid[4]
group = uidGid[5]
# Создаем пользовательскую директорию
self.clVars.Set('cl_root_path',homeDir,True)
homeExists = os.path.exists(homeDir)
if homeExists:
self.printWARNING(_("Home dir %s exists")%homeDir)
if set(os.listdir(homeDir))-set(["Home","Disks"]):
if not applyAlways:
# Получаем пути к профилям постоянного наложения
alwProfilePath = self.getAlwaysProfilePath()
if not alwProfilePath:
return True
# Записываем пути к профилям постоянного наложения
#в переменную
self.printSUCCESS(_("Apply always profiles") + " ...")
self.clVars.Set('cl_profile_path',alwProfilePath, True)
if not os.path.exists(homeDir):
self.createUserDir(uid, gid, homeDir)
# Записываем переменные
self.clVars.Set('ur_login',userName)
self.clVars.Set('ur_fullname',fullName)
self.clVars.Set('ur_mail',mail)
self.clVars.Set('ur_group',group)
# Применяем профили для пользователя
dirsAndFiles = self.applyProfilesFromUser()
if not dirsAndFiles:
self.printERROR(_("Not apply user profile"))
return False
self.chownR(homeDir, uid, gid, dirsAndFiles)
if not homeExists:
self.printSUCCESS(_("Created home dir %s")%homeDir + " ...")
self.printSUCCESS(_("User account is configured") + " ...")
return True
def isDomain(self):
"""Находится ли компьютер в домене"""
self.createClVars(self.clVars)
foundMountRemote =self.isMount("/var/calculate/remote" ,"cifs")
foundMountHome =self.isMount("/var/calculate/home" ,"none", False)
if not self.clVars.Get("cl_remote_host") and not foundMountRemote and\
not foundMountHome:
self.printERROR("The computer is not in domain")
return False
return (foundMountRemote,foundMountHome)
def isMount(self, pathMount ,typeMount, secondPath=True):
"""Примонтирована ли директория"""
path = os.path.realpath(pathMount)
foundMount = False
if secondPath:
reFoundMount = re.compile("on\s+%s\s+type\s+%s"%(path,typeMount))
else:
reFoundMount = re.compile("%s\s+.+type\s+%s"%(path,typeMount))
resMount = self.execProg("mount",False,False)
if resMount and type(resMount) == types.ListType:
for string in resMount:
if reFoundMount.search(string):
foundMount = True
break
return foundMount
def mountRemote(self):
self.createClVars(self.clVars)
foundMount = self.isDomain()
if not foundMount:
return False
foundMountRemote = foundMount[0]
foundMountHome = foundMount[1]
pathHome = "/var/calculate/home"
if foundMountRemote:
self.printWARNING(_("Samba resource [remote] is mount") + \
" ...")
if foundMountHome:
self.printWARNING(str(pathHome) + " " +_("is mount")+
" ...")
if foundMountHome and foundMountRemote:
return True
if not foundMountRemote:
pathRemote = "/var/calculate/remote"
domain = self.clVars.Get("cl_remote_host")
pwdRemote = self.clVars.Get("cl_remote_pw")
if not (domain and pwdRemote):
self.printERROR(_("Not found vaiables: cl_remote_host or \
cl_remote_pw") + " ...")
return False
if not os.path.exists(pathRemote):
os.makedirs(pathRemote)
mountStr = "mount -t cifs -o user=client,password=%s \
//%s/remote %s" %(pwdRemote,domain,pathRemote)
textLine = self.execProg(mountStr)
if not (textLine == None):
self.printERROR(_("Can not mount Samba resource [remote]") +\
" ...")
return False
self.printSUCCESS(_("Mount Samba resource [remote]") +\
" ...")
if not foundMountHome:
if not os.path.exists(pathHome):
os.makedirs(pathHome)
mountStr = "mount -o bind %s /home" %pathHome
textLine = self.execProg(mountStr)
if not (textLine == None):
self.printERROR(_("Can not mount") + " " + str(pathHome) +\
" ...")
return False
self.printSUCCESS(_("Mount") + " " + str(pathHome) + " " +\
" ...")
return True
def delDomain(self):
"""выводим из домена"""
self.createClVars()
pathRemote = "/var/calculate/remote"
pathHome = "/var/calculate/home"
foundMountRemote =self.isMount(pathRemote ,"cifs")
foundMountHome =self.isMount(pathHome ,"none",False)
domain = self.clVars.Get("cl_remote_host")
if not domain:
self.printWARNING("The computer is not in domain")
return True
if foundMountRemote:
umountStr = "umount %s"%(pathRemote)
textLine = self.execProg(umountStr)
if not (textLine == None):
self.printERROR(_("Can not umount Samba resource [remote]") + \
" ...")
return False
if foundMountHome:
umountStr = "umount %s"%(pathHome)
textLine = self.execProg(umountStr)
if not (textLine == None):
self.printERROR(_("Can not umount") + " " + pathHome +\
" ...")
return False
self.execProg("calculate -P install/6intranet")
self.clVars.Delete("cl_remote_host","local")
self.clVars.Delete("cl_remote_pw","local")
self.printOK(_("Computer removed from domain %s")%domain + " ...")
return True
def addDomain(self, domain):
"""Вводим в домен"""
# Создаем объект переменных
self.createClVars()
resPing = self.execProg("ping -c 2 -i 0.3 %s" %domain,False,False)
foudHost = False
foudHostSamba = False
foundMountRemote = False
reFoundHost = re.compile("(\d+)\% packet loss")
if resPing and type(resPing) == types.ListType and len(resPing)>=2:
pingStr = resPing[-2].strip()
reSearch = reFoundHost.search(pingStr)
if reSearch and reSearch.group(1) == "0":
foudHost = True
if not foudHost:
self.printERROR(_("Not found domain %s")%domain)
return False
reFoundHostSamba = re.compile("Server=\[Samba.+\]")
resSmbClient = self.execProg("smbclient -N -L %s" %domain,
False,False)
if resSmbClient and type(resSmbClient) == types.ListType:
for string in resSmbClient:
if reFoundHostSamba.search(string):
foudHostSamba = True
break
if not foudHostSamba:
self.printERROR(_("Not found Samba server in %s")%domain)
return False
if self.clVars.Get("cl_remote_host") and \
self.clVars.Get("cl_remote_host") != domain:
if not self.delDomain():
return False
foundMountRemote =self.isMount("/var/calculate/remote" ,"cifs")
foundMountHome =self.isMount("/var/calculate/home" ,"none", False)
if foundMountRemote:
self.printWARNING(_("Samba resource [remote] mount") + \
" ...")
else:
userPwd = self.getUserPassword("Domain password for the desktop")
pathRemote = "/var/calculate/remote"
pwdRemote = userPwd
if not os.path.exists(pathRemote):
os.makedirs(pathRemote)
mountStr = "mount -t cifs -o user=client,password=%s \
//%s/remote %s" %(pwdRemote,domain,pathRemote)
textLine = self.execProg(mountStr)
if not (textLine == None):
self.printERROR(_("Can not mount Samba resource [remote]") + \
" ...")
return False
else:
self.printSUCCESS(_("Mount Samba resource [remote]") + \
" ...")
self.clVars.Write("cl_remote_host", domain, False, "local")
self.clVars.Write("cl_remote_pw", userPwd, False, "local")
pathHome = "/var/calculate/home"
if foundMountHome:
self.printWARNING(str(pathHome)+ " " +_("is mount")+
" ...")
else:
if not os.path.exists(pathHome):
os.makedirs(pathHome)
mountStr = "mount -o bind %s /home" %pathHome
textLine = self.execProg(mountStr)
if not (textLine == None):
self.printERROR(_("Can not mount") + " " + str(pathHome) +\
" ...")
return False
self.printSUCCESS(_("Mount") + " " + str(pathHome) + " " +\
" ...")
self.clVars.flIniFile()
#считаем переменные для клиента
servDn = self.clVars.Get("ld_services_dn")
unixDN = self.clVars.Get("ld_unix_dn")
bindDn = self.clVars.Get("ld_bind_dn")
bindPw = self.clVars.Get("ld_bind_pw")
# запишем их
if not (servDn and unixDN and bindDn and bindPw):
self.printERROR(_("Not found variables:"))
self.printERROR("ld_services_dn or ld_unix_dn \
or ld_bind_dn or ld_bind_pw")
return False
execStr = "calculate --set-server_url=%s --set-ldap_base=%s \
--set-ldap_root=%s --set-ldap_bind=%s --set-ldap_bindpw=%s -P \
install/6intranet" %(domain,servDn,unixDN,bindDn,bindPw)
self.execProg(execStr)
textLine = self.execProg("/etc/init.d/dbus restart")
if not "ok" in textLine:
self.printWARNING(_("Error restarting /etc/init.d/dbus")+ " ...")
return False
self.printOK(_("Computer added to domain %s")%domain + " ...")
return True
def umountUserRes(self, userName):
"""Отмонтирование пользовательских ресурсов и синхронизация настроек"""
self.createClVars()
# В случае компьютера вне домена
if not self.clVars.Get("cl_remote_host"):
self.printSUCCESS(_("To be used by local profile."))
return True
connectDomain = self.isDomain()
if not connectDomain:
return False
elif not connectDomain[0]:
self.printERROR(_("Can not mount Samba resource [remote]") + \
" ...")
return False
# Подсоединяемся к серверу
domain = self.clVars.Get("cl_remote_host")
if not self.getLdapObjBind(domain):
return False
# homeDir из LDAP
resLdap = self.getUserLdapInfo(userName)
if not resLdap:
return False
homeDir = resLdap[4]
home = os.path.split(homeDir)[0]
pathRemote = []
# Удаленный ресурс профилей
pathRemote.append((os.path.join(home,"." + userName), "unix"))
# Удаленный ресурс home
pathRemote.append((os.path.join(homeDir,"Home"), "homes"))
# Удаленный ресурс share
pathRemote.append((os.path.join(homeDir,"Disks"), "share"))
if not self.syncUser(userName, homeDir, "logout"):
return False
flagError = False
for path, res in pathRemote:
if self.isMount(path ,"cifs"):
textLine = self.execProg("umount %s"%path)
if not (textLine == None):
self.printERROR(_("Can not umount Samba resource \
[%s]")%res + " ...")
flagError = True
break
if os.path.exists(path) and not os.listdir(path):
try:
os.rmdir(path)
except:
self.printERROR(_("Can not remove dir %s")% path)
flagError = True
break
if flagError:
self.printERROR(_("Keep a user profile in the domain"))
return False
self.printSUCCESS(_("Keep a user profile in the domain"))
self.printOK(_("Umount user resource in domain") + " ...")
return True
def umountUserResNoSync(self, userName):
"""Отмонтирование пользовательских ресурсов
без синхронизации настроек"""
self.createClVars(self.clVars)
# В случае компьютера вне домена
if not self.clVars.Get("cl_remote_host"):
self.printSUCCESS(_("To be used by local profile."))
return True
# Подсоединяемся к серверу
domain = self.clVars.Get("cl_remote_host")
if not self.getLdapObjBind(domain):
return False
# homeDir из LDAP
resLdap = self.getUserLdapInfo(userName)
if not resLdap:
return False
homeDir = resLdap[4]
home = os.path.split(homeDir)[0]
pathRemote = []
# Удаленный ресурс профилей
pathRemote.append((os.path.join(home,"." + userName), "unix"))
# Удаленный ресурс home
pathRemote.append((os.path.join(homeDir,"Home"), "homes"))
# Удаленный ресурс share
pathRemote.append((os.path.join(homeDir,"Disks"), "share"))
flagError = False
for path, res in pathRemote:
if self.isMount(path ,"cifs"):
textLine = self.execProg("umount %s"%path)
if not (textLine == None):
self.printERROR(_("Can not umount dir %s")%path + " ...")
flagError = True
break
if os.path.exists(path) and not os.listdir(path):
try:
os.rmdir(path)
except:
self.printERROR(_("Can not remove dir %s")% path)
flagError = True
break
if flagError:
self.printERROR(_("Can not umount user %s resource")%userName)
return False
self.printOK(_("Umount user %s resource") %userName + " ...")
return True
def mountUserRes(self, userName, sync=True):
"""Монтирование пользовательских ресурсов и синхронизация настроек"""
self.createClVars()
# В случае компьютера вне домена
if not self.clVars.Get("cl_remote_host"):
self.printSUCCESS(_("To be used by local profile."))
return True
# Проверим что компьютер в домене и смонтирован [remote]
connectDomain = self.isDomain()
if not connectDomain:
return False
elif not connectDomain[0]:
self.printERROR(_("Can not mount Samba resource [remote]") + \
" ...")
return False
# Подсоединяемся к серверу
domain = self.clVars.Get("cl_remote_host")
if not self.getLdapObjBind(domain):
return False
# homeDir из LDAP
resLdap = self.getUserLdapInfo(userName)
if not resLdap:
return False
uid = int(resLdap[0])
gid = int(resLdap[1])
homeDir = resLdap[4]
# При отсуствии создаем домашнюю директорию
if not os.path.exists(homeDir):
os.makedirs(homeDir)
os.chown(homeDir,uid,gid)
os.chmod(homeDir,0700)
# Получаем пароль пользователя из ключей ядра
userPwd = _cl_keys.getKey(userName)
if not userPwd:
self.printERROR(_("Not found user password"))
return False
home = os.path.split(homeDir)[0]
pathRemote = []
# Удаленный ресурс профилей
pathRemote.append((os.path.join(home,"." + userName), "unix"))
# Удаленный ресурс home
pathRemote.append((os.path.join(homeDir,"Home"), "homes"))
# Удаленный ресурс share
pathRemote.append((os.path.join(homeDir,"Disks"), "share"))
flagError = False
i = 0
for path, res in pathRemote:
i += 1
# Создаем директории для монтирования
if not os.path.exists(path):
try:
os.mkdir(path)
os.chown(path, uid, gid)
os.chmod(path,0700)
except OSError:
self.printERROR(_("Error creating directory"))
self.printERROR(_("Permission denied: '%s'")%path)
flagError = True
break
# Проверяем на монтирование директории
if self.isMount(path, 'cifs'):
continue
if i==3:
# Монтируем директории c uid
mountStr="mount -t cifs -o user=%s,password=%s,uid=%s,gid=%s"\
%(userName,userPwd,uid,gid) + " " +\
"//%s/%s %s" %(self.clVars.Get("cl_remote_host"),
res, path)
else:
# Монтируем директории
mountStr="mount -t cifs -o user=%s,password=%s"%(userName,
userPwd) + " " +\
"//%s/%s %s" %(self.clVars.Get("cl_remote_host"),
res, path)
textLine = self.execProg(mountStr)
if not (textLine == None):
self.printERROR(_("Can not mount Samba resource [%s]")%res + \
" ...")
flagError = True
break
if flagError:
return False
# Синхронизируем настройки
if sync:
if not self.syncUser(userName, homeDir, "login"):
return False
self.printSUCCESS(_("Mount user resource in domain"))
self.printOK(_("Get a user profile in the domain") + " ...")
return True
def syncUser(self, userName, userHome, sync):
"""Синхронизация пользовательских настроек"""
home = os.path.split(userHome)[0]
homeProfile = os.path.join(home,"." + userName)
flagError = False
execStr = ""
if sync == "login":
if os.path.exists(userHome) and\
os.path.exists(homeProfile):
execStr = '/usr/bin/rsync --delete-excluded --delete \
--exclude="/.googleearth" --exclude="/Home" --exclude="/Disks" --exclude="*~" \
--filter="P /.googleearth" --filter="P /Home" --filter="P /Disks" -a -x \
%s/ %s/' %(homeProfile,userHome)
elif sync == "logout":
if os.path.exists(userHome) and os.listdir(userHome) and\
os.path.exists(homeProfile):
execStr = '/usr/bin/rsync --delete-excluded --delete \
--exclude="/.googleearth" --exclude="/Home" --exclude="/Disks" --exclude="*~" \
--exclude="/.kde4/cache-*" --exclude="/.kde4/tmp-*" \
--exclude="/.kde4/socket-*" --filter="P /.googleearth" --filter="P /Home" \
--filter="P /Disks" -a -b -x %s/ %s/'%(userHome,homeProfile)
else:
self.printERROR(_("Method syncUser: option sync=%s incorrect")\
%str(sync))
return False
if execStr:
textLine = self.execProg(execStr)
if not (textLine == None):
self.printERROR(_("Can not rsync") + " " + str(sync) +\
" ...")
flagError = True
else:
if sync == "login":
if not (os.path.exists(userHome)):
self.printERROR(_("Directory %s not exists")%userHome)
else:
self.printERROR(_("Directory %s not exists")%homeProfile)
elif sync == "logout":
if not (os.path.exists(userHome)):
self.printERROR(_("Directory %s is empty or not exists")\
%userHome)
else:
self.printERROR(_("Directory %s not exists")%homeProfile)
flagError = True
if flagError:
return False
else:
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:
if not self.opt:
self.printErrorNotOpt()
self.flagHelp = True
elif not self.opt and not self.params.has_key('user'):
print helpObj.getHelp(helpObj.relOptions['h'])
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