|
|
|
|
#-*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
# Copyright 2010 Calculate Ltd. http://www.calculate-linux.org
|
|
|
|
|
#
|
|
|
|
|
# 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 stat
|
|
|
|
|
import re
|
|
|
|
|
import sys
|
|
|
|
|
import pwd
|
|
|
|
|
|
|
|
|
|
import subprocess
|
|
|
|
|
import ldap
|
|
|
|
|
import time
|
|
|
|
|
import types
|
|
|
|
|
|
|
|
|
|
import getpass
|
|
|
|
|
|
|
|
|
|
from datavars import DataVarsClient, DataVars, __version__,__app__
|
|
|
|
|
|
|
|
|
|
from calculate.lib.cl_template import (Template, iniParser,TemplatesError,
|
|
|
|
|
ProgressTemplate)
|
|
|
|
|
from calculate.lib.cl_print import color_print
|
|
|
|
|
from calculate.lib.cl_ldap import ldapUser
|
|
|
|
|
from calculate.lib.utils.ip import Pinger, isOpenPort, IPError
|
|
|
|
|
from calculate.lib.utils.files import (runOsCommand, getModeFile, removeDir,
|
|
|
|
|
isMount,pathJoin,tarLinks)
|
|
|
|
|
from calculate.lib.utils.common import (getpathenv, appendProgramToEnvFile,
|
|
|
|
|
removeProgramToEnvFile)
|
|
|
|
|
from _cl_keys import getKey, clearKey
|
|
|
|
|
from calculate.lib.convertenv import convertEnv
|
|
|
|
|
from calculate.lib.encrypt import encrypt
|
|
|
|
|
from cl_client_cache import userCache
|
|
|
|
|
from shutil import copy2
|
|
|
|
|
from socket import gethostbyname
|
|
|
|
|
import tarfile
|
|
|
|
|
from collections import OrderedDict
|
|
|
|
|
|
|
|
|
|
from calculate.core.server.func import safetyWrapper
|
|
|
|
|
|
|
|
|
|
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
|
|
|
|
|
setLocalTranslate('cl_client3',sys.modules[__name__])
|
|
|
|
|
__ = getLazyLocalTranslate(_)
|
|
|
|
|
|
|
|
|
|
class ClientError(Exception):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
class RsyncProgressBar:
|
|
|
|
|
"""
|
|
|
|
|
Rsync with using setProgress
|
|
|
|
|
"""
|
|
|
|
|
# get number of send file from info rsync stream
|
|
|
|
|
senderre = re.compile("\[sender\] i=(\d+) ", re.S)
|
|
|
|
|
# get number of receivce file from info rsync rtream
|
|
|
|
|
receiverre = re.compile("recv_generator\(.+,([0-9]+)\)", re.S)
|
|
|
|
|
pipe = None
|
|
|
|
|
maximum = 1
|
|
|
|
|
copyStarting = False
|
|
|
|
|
|
|
|
|
|
def __init__(self, title, secondtitle, rsyncstr, parent,maximum=1):
|
|
|
|
|
self.title = title
|
|
|
|
|
self.secondtitle = secondtitle
|
|
|
|
|
self.maximum = maximum
|
|
|
|
|
self.rsyncstr = rsyncstr
|
|
|
|
|
self.parent = parent
|
|
|
|
|
self.value = 0
|
|
|
|
|
|
|
|
|
|
def getFilesNum(self):
|
|
|
|
|
"""
|
|
|
|
|
Get files count created by generator
|
|
|
|
|
"""
|
|
|
|
|
if self.pipe:
|
|
|
|
|
return self.value
|
|
|
|
|
|
|
|
|
|
def getExitCode(self):
|
|
|
|
|
"""
|
|
|
|
|
Get rsync exitcode
|
|
|
|
|
"""
|
|
|
|
|
if self.pipe:
|
|
|
|
|
return self.pipe.wait()
|
|
|
|
|
return 255
|
|
|
|
|
|
|
|
|
|
def getErrMessage(self):
|
|
|
|
|
"""
|
|
|
|
|
Rsync error message
|
|
|
|
|
"""
|
|
|
|
|
if self.pipe:
|
|
|
|
|
return self.pipe.stderr.read()
|
|
|
|
|
return _("RsyncProgressBar: Wrong pipe")
|
|
|
|
|
|
|
|
|
|
def runsilent(self):
|
|
|
|
|
"""
|
|
|
|
|
Run rsync without progressbar
|
|
|
|
|
"""
|
|
|
|
|
self.pipe = subprocess.Popen(self.rsyncstr, stdin=subprocess.PIPE,
|
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
|
close_fds=True, shell=True)
|
|
|
|
|
while True:
|
|
|
|
|
s = self.pipe.stdout.readline()
|
|
|
|
|
if len(s) == 0:
|
|
|
|
|
break
|
|
|
|
|
q = self.receiverre.search(s)
|
|
|
|
|
if q:
|
|
|
|
|
self.value = int(q.groups()[0])
|
|
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
|
"""
|
|
|
|
|
Run rsync with progressbar
|
|
|
|
|
"""
|
|
|
|
|
self.parent.startTask(self.title,progress=True)
|
|
|
|
|
self.pipe = subprocess.Popen(self.rsyncstr, stdin=subprocess.PIPE,
|
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
|
close_fds=True, shell=True)
|
|
|
|
|
oldpercent = 0
|
|
|
|
|
while True:
|
|
|
|
|
s = self.pipe.stdout.readline()
|
|
|
|
|
if len(s) == 0:
|
|
|
|
|
break
|
|
|
|
|
q = self.receiverre.search(s)
|
|
|
|
|
if q:
|
|
|
|
|
if not self.copyStarting:
|
|
|
|
|
self.parent.endTask()
|
|
|
|
|
self.parent.startTask(self.secondtitle,progress=True)
|
|
|
|
|
#self.parent.setProgress(0)
|
|
|
|
|
self.copyStarting = True
|
|
|
|
|
self.value = int(q.groups()[0])
|
|
|
|
|
if self.maximum:
|
|
|
|
|
newvalue = int(100*self.value / self.maximum)
|
|
|
|
|
newvalue = min(newvalue,99)
|
|
|
|
|
if newvalue > oldpercent:
|
|
|
|
|
self.parent.setProgress(newvalue)
|
|
|
|
|
oldpercent = newvalue
|
|
|
|
|
self.parent.setProgress(100)
|
|
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
|
self.parent.endTask()
|
|
|
|
|
|
|
|
|
|
class ldapData(ldapUser):
|
|
|
|
|
"""LDAP methods"""
|
|
|
|
|
|
|
|
|
|
def addDN(self, *arg):
|
|
|
|
|
"""
|
|
|
|
|
Append text DN elements
|
|
|
|
|
"""
|
|
|
|
|
DNs = []
|
|
|
|
|
for dn in arg:
|
|
|
|
|
if dn:
|
|
|
|
|
DNs.append(dn)
|
|
|
|
|
return ','.join(DNs)
|
|
|
|
|
|
|
|
|
|
def getReplDN(self):
|
|
|
|
|
"""
|
|
|
|
|
Get from LDAP last domain server
|
|
|
|
|
|
|
|
|
|
Branch has ((username,systemname,host))
|
|
|
|
|
"""
|
|
|
|
|
usersDN = self.getUsersDN()
|
|
|
|
|
if usersDN:
|
|
|
|
|
partDN = "ou=Worked,ou=Replication,ou=LDAP"
|
|
|
|
|
servicesDN = "ou=Services"
|
|
|
|
|
baseDN = usersDN.rpartition(servicesDN+",")[2]
|
|
|
|
|
replDN = self.addDN(partDN, servicesDN, baseDN)
|
|
|
|
|
return replDN
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def searchPrevHost(self, userName, osLinuxShort):
|
|
|
|
|
"""Find server which user use"""
|
|
|
|
|
connectData = self.getBindConnectData()
|
|
|
|
|
if connectData:
|
|
|
|
|
bindDn, bindPw, host = connectData
|
|
|
|
|
replDN = self.getReplDN()
|
|
|
|
|
# find string for service replication branch
|
|
|
|
|
userAndOsName = "%s@%s"%(userName,osLinuxShort)
|
|
|
|
|
findAttr = "uid=%s"%userAndOsName
|
|
|
|
|
# connect to LDAP
|
|
|
|
|
if not self.ldapConnect(bindDn, bindPw, host):
|
|
|
|
|
return False
|
|
|
|
|
resSearch = self.ldapObj.ldapSearch(replDN, ldap.SCOPE_ONELEVEL,
|
|
|
|
|
findAttr, ["host"])
|
|
|
|
|
return resSearch
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _gethostbyname(self,hostname):
|
|
|
|
|
try:
|
|
|
|
|
return gethostbyname(hostname)
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def getNameRemoteServer(self,userName, osLinuxShort, curHost):
|
|
|
|
|
"""
|
|
|
|
|
Get remote domain hostname or empty if profile is keeped on
|
|
|
|
|
current server
|
|
|
|
|
"""
|
|
|
|
|
searchPrevHost = self.searchPrevHost(userName, osLinuxShort)
|
|
|
|
|
if searchPrevHost and searchPrevHost[0][0][1].has_key('host'):
|
|
|
|
|
prevHost = searchPrevHost[0][0][1]['host'][0]
|
|
|
|
|
else:
|
|
|
|
|
prevHost = None
|
|
|
|
|
# get ip address of previous server and current server
|
|
|
|
|
prevIp = self._gethostbyname(prevHost)
|
|
|
|
|
curIp = self._gethostbyname(curHost)
|
|
|
|
|
# if actual profile not found or on local
|
|
|
|
|
if not prevHost or curIp and prevIp == curIp:
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
return prevHost
|
|
|
|
|
|
|
|
|
|
def isRepl(self):
|
|
|
|
|
"""
|
|
|
|
|
Is on or off replication on server
|
|
|
|
|
"""
|
|
|
|
|
connectData = self.getBindConnectData()
|
|
|
|
|
if connectData:
|
|
|
|
|
bindDn, bindPw, host = connectData
|
|
|
|
|
usersDN = self.getUsersDN()
|
|
|
|
|
partDN = "ou=Replication,ou=LDAP"
|
|
|
|
|
servicesDN = "ou=Services"
|
|
|
|
|
baseDN = usersDN.rpartition(servicesDN+",")[2]
|
|
|
|
|
replDN = self.addDN(partDN, servicesDN, baseDN)
|
|
|
|
|
findAttr = "ou=Worked"
|
|
|
|
|
# connect to LDAP
|
|
|
|
|
if not self.ldapConnect(bindDn, bindPw, host):
|
|
|
|
|
return False
|
|
|
|
|
resSearch = self.ldapObj.ldapSearch(replDN, ldap.SCOPE_ONELEVEL,
|
|
|
|
|
findAttr,
|
|
|
|
|
[findAttr.partition("=")[0]])
|
|
|
|
|
if resSearch:
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
class commandServer(color_print):
|
|
|
|
|
"""Server command object"""
|
|
|
|
|
|
|
|
|
|
def setServerCommand(self, command, varsCommand, fileConfig,
|
|
|
|
|
uid=None, gid=None):
|
|
|
|
|
"""Set server command"""
|
|
|
|
|
pathConfig = os.path.split(fileConfig)[0]
|
|
|
|
|
# create user config directory
|
|
|
|
|
if not os.path.exists(pathConfig):
|
|
|
|
|
os.makedirs(pathConfig)
|
|
|
|
|
if not uid is None and not gid is None:
|
|
|
|
|
os.chown(pathConfig, uid, gid)
|
|
|
|
|
objConfig = iniParser(fileConfig)
|
|
|
|
|
varsRun = {"run":"on"}
|
|
|
|
|
varsRun.update(varsCommand)
|
|
|
|
|
if not objConfig.setVar(["command"]+command, varsRun):
|
|
|
|
|
raise ClientError(_("Failed to write variables in file %s")\
|
|
|
|
|
%fileConfig)
|
|
|
|
|
if not uid is None and not gid is None:
|
|
|
|
|
os.chown(fileConfig, uid, gid)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def checkUserPwdLDAP(self, server, userDN, password):
|
|
|
|
|
"""Проверка пароля Unix пользователя на сервере"""
|
|
|
|
|
ldapInit = ldap.initialize("ldap://%s"%server)
|
|
|
|
|
errMessage = ""
|
|
|
|
|
try:
|
|
|
|
|
ldapInit.bind_s(userDN, password)
|
|
|
|
|
except ldap.INVALID_CREDENTIALS:
|
|
|
|
|
errMessage = _("Wrong password")
|
|
|
|
|
return False, errMessage
|
|
|
|
|
except ldap.LDAPError, e:
|
|
|
|
|
errMessage = e[0]['desc']
|
|
|
|
|
return False, errMessage
|
|
|
|
|
return True, errMessage
|
|
|
|
|
|
|
|
|
|
def getUserPwd(self, options, optDialog, optStdIn, pwDialog=False):
|
|
|
|
|
"""Получить пароль у пользователя
|
|
|
|
|
|
|
|
|
|
options - полученные опции командной строки
|
|
|
|
|
optDialog - опция командной строки для вывода диалога для получения
|
|
|
|
|
пароля
|
|
|
|
|
optStdIn - опция командной строки для получения пароля из
|
|
|
|
|
стандартного ввода (stdin)
|
|
|
|
|
pwDialog - структура для вывода приглашения в режиме диалога
|
|
|
|
|
"""
|
|
|
|
|
userPwd = ""
|
|
|
|
|
if optStdIn and options.has_key(optStdIn):
|
|
|
|
|
pwdA = sys.stdin.readline().rstrip()
|
|
|
|
|
pwdB = sys.stdin.readline().rstrip()
|
|
|
|
|
elif optDialog and options.has_key(optDialog):
|
|
|
|
|
if not pwDialog:
|
|
|
|
|
pwDialog = [_("New password"),
|
|
|
|
|
_("Retype the new password")]
|
|
|
|
|
pwdA = getpass.getpass(pwDialog[0]+":")
|
|
|
|
|
pwdB = getpass.getpass(pwDialog[1]+":")
|
|
|
|
|
if (optStdIn and options.has_key(optStdIn)) or\
|
|
|
|
|
(optDialog and options.has_key(optDialog)):
|
|
|
|
|
if not pwdA or not (pwdA == pwdB):
|
|
|
|
|
self.printERROR (_("ERROR") + ": " +\
|
|
|
|
|
_("passwords do not match"))
|
|
|
|
|
return False
|
|
|
|
|
userPwd = pwdA
|
|
|
|
|
return userPwd
|
|
|
|
|
|
|
|
|
|
class Client(commandServer, encrypt):
|
|
|
|
|
"""
|
|
|
|
|
Client logic object
|
|
|
|
|
|
|
|
|
|
Has fundamental methods:
|
|
|
|
|
mountUserResAndSync - mount user resources and sync profile from server
|
|
|
|
|
umountUserResAndSync - umount user resources and sync profile to server
|
|
|
|
|
mountRemote - mount remote domain resource
|
|
|
|
|
delDomain - remove workstation from domain
|
|
|
|
|
addDomain - add workstation to domain
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# object for user data in LDAP
|
|
|
|
|
ldapDataObj = ldapData()
|
|
|
|
|
# user calculate config directory
|
|
|
|
|
pathConfig = ".calculate"
|
|
|
|
|
# client soft config file
|
|
|
|
|
configFileSoft = os.path.join(pathConfig, "ini.env")
|
|
|
|
|
# client config file
|
|
|
|
|
configFileDesktop = os.path.join(pathConfig, "desktop.env")
|
|
|
|
|
# client config for server
|
|
|
|
|
configFileServer = os.path.join(pathConfig, "server.env")
|
|
|
|
|
# file list of user profile
|
|
|
|
|
listTemplFile = os.path.join(pathConfig, "files.txt")
|
|
|
|
|
|
|
|
|
|
# files which not cleaning from user home directory
|
|
|
|
|
skipHomeFile = ["Home","Disks","Share","FTP",configFileDesktop]
|
|
|
|
|
|
|
|
|
|
# option dict of services from /var/calculate/remote/server.env
|
|
|
|
|
optionsInfo = {}
|
|
|
|
|
|
|
|
|
|
# convertation object from old remote env
|
|
|
|
|
convObj = None
|
|
|
|
|
# private user files
|
|
|
|
|
privateFiles = [configFileServer]
|
|
|
|
|
# private user directories
|
|
|
|
|
privateDirs = []
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.clVars = None
|
|
|
|
|
self.clTempl = None
|
|
|
|
|
|
|
|
|
|
def initVars(self,datavars=None):
|
|
|
|
|
"""Primary variables initialization"""
|
|
|
|
|
if not datavars:
|
|
|
|
|
self.clVars = DataVarsClient()
|
|
|
|
|
self.clVars.importClient()
|
|
|
|
|
self.clVars.flIniFile()
|
|
|
|
|
else:
|
|
|
|
|
self.clVars = datavars
|
|
|
|
|
|
|
|
|
|
def removeVars(self):
|
|
|
|
|
"""
|
|
|
|
|
Remove domain variables. Useing on remove package
|
|
|
|
|
and undomain action
|
|
|
|
|
"""
|
|
|
|
|
self.clVars.Delete("cl_remote_host", "local")
|
|
|
|
|
self.clVars.Delete("cl_remote_pw", "local")
|
|
|
|
|
self.clVars.Delete("os_remote_auth")
|
|
|
|
|
self.clVars.Delete("os_remote_client")
|
|
|
|
|
self.clVars.Set("cl_remote_host", "", True)
|
|
|
|
|
self.clVars.Set("cl_remote_pw", "", True)
|
|
|
|
|
self.clVars.Set("os_remote_auth", "", True)
|
|
|
|
|
self.clVars.Set("os_remote_client", "", True)
|
|
|
|
|
|
|
|
|
|
def applyTemplatesFromSystem(self):
|
|
|
|
|
"""Apply templates for system"""
|
|
|
|
|
if self.clVars.Get('cl_action') == 'domain':
|
|
|
|
|
self.startTask(_("Appling domain templates"),progress=True)
|
|
|
|
|
else:
|
|
|
|
|
self.startTask(_("Appling undomain templates"),progress=True)
|
|
|
|
|
if self.clTempl:
|
|
|
|
|
self.closeClTemplate()
|
|
|
|
|
self.clTempl = ProgressTemplate(self.setProgress,self.clVars,
|
|
|
|
|
cltObj=True)
|
|
|
|
|
dirsFiles = self.clTempl.applyTemplates()
|
|
|
|
|
if self.clTempl.getError():
|
|
|
|
|
self.printERROR(self.clTempl.getError().strip())
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
self.endTask()
|
|
|
|
|
return dirsFiles
|
|
|
|
|
|
|
|
|
|
def isTwoSessionsUser(self, userName):
|
|
|
|
|
"""
|
|
|
|
|
Check on second user login
|
|
|
|
|
"""
|
|
|
|
|
xSession = False
|
|
|
|
|
foundTwoSession = False
|
|
|
|
|
resWho = self.execProg("who")
|
|
|
|
|
if resWho:
|
|
|
|
|
for pattern in ("%s\s+\d+\s+","%s\s+tty\d+.*:\d+"):
|
|
|
|
|
reFoundUser = re.compile(pattern%(userName))
|
|
|
|
|
for string in resWho:
|
|
|
|
|
if reFoundUser.search(string):
|
|
|
|
|
if xSession:
|
|
|
|
|
self.printERROR(\
|
|
|
|
|
_("Second X session for user %s cannot be opened.")\
|
|
|
|
|
%userName)
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
xSession = True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def isDomain(self):
|
|
|
|
|
"""
|
|
|
|
|
Check domain or not workstation
|
|
|
|
|
"""
|
|
|
|
|
foundMountRemote = isMount("/var/calculate/remote")
|
|
|
|
|
remoteHost = self.clVars.Get("cl_remote_host")
|
|
|
|
|
if remoteHost and foundMountRemote:
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def getSyncStatus(self,rpath):
|
|
|
|
|
"""
|
|
|
|
|
Get local config 'date' and 'status_sync' or None
|
|
|
|
|
"""
|
|
|
|
|
fileConfig = os.path.join(rpath, self.configFileDesktop)
|
|
|
|
|
# get data from desktop config on success run get by archive
|
|
|
|
|
if os.path.exists(fileConfig):
|
|
|
|
|
objConfig = iniParser(fileConfig)
|
|
|
|
|
data = self.getDataInConfig("main", ["status_sync"],
|
|
|
|
|
objConfig)
|
|
|
|
|
if data:
|
|
|
|
|
return data.get("status_sync",None)
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def getUserMountResources(self, userName, homeDir, flagRemoteServer):
|
|
|
|
|
"""
|
|
|
|
|
Get information about remote profile resource
|
|
|
|
|
"""
|
|
|
|
|
home = os.path.split(homeDir)[0]
|
|
|
|
|
dictResources = OrderedDict(# share resource
|
|
|
|
|
share={"resource":"share",
|
|
|
|
|
"path":os.path.join(homeDir,"Share")},
|
|
|
|
|
profile={"resource":"unix",
|
|
|
|
|
"path":os.path.join(home,"."+userName)},
|
|
|
|
|
# resource - home directory
|
|
|
|
|
home={"resource":"homes",
|
|
|
|
|
"path":os.path.join(homeDir,"Home")})
|
|
|
|
|
if self.getInfoService("ftp", "host"):
|
|
|
|
|
# resource ftp
|
|
|
|
|
dictResources["ftp"] = {"resource":"ftp",
|
|
|
|
|
"path":os.path.join(homeDir,"FTP")}
|
|
|
|
|
if flagRemoteServer:
|
|
|
|
|
# remote user profile
|
|
|
|
|
dictResources["remote_profile"] = {"resource":"unix",
|
|
|
|
|
"path":os.path.join(home,"."+userName+"."+"remote")}
|
|
|
|
|
return dictResources
|
|
|
|
|
|
|
|
|
|
def mountSambaRes(self,host,userName,userPwd,uid,gid,res,rpath,
|
|
|
|
|
mountUidList=['ftp','homes','share']):
|
|
|
|
|
"""Mount samba resource"""
|
|
|
|
|
if res in mountUidList:
|
|
|
|
|
# mount by uid
|
|
|
|
|
mountStr = "mount -t cifs -o user=%s,uid=%s,gid=%s,noperm"\
|
|
|
|
|
%(userName,uid,gid) +\
|
|
|
|
|
" //%s/%s %s" %(host, res, rpath)
|
|
|
|
|
else:
|
|
|
|
|
# mount by root
|
|
|
|
|
mountStr = "mount -t cifs -o user=%s"%(userName)+\
|
|
|
|
|
" //%s/%s %s" %(host, res, rpath)
|
|
|
|
|
textLine = self.execProg(mountStr, envProg={"PASSWD":userPwd})
|
|
|
|
|
return textLine
|
|
|
|
|
|
|
|
|
|
def mountSleepRes(self,host,userPwd,res,rpath):
|
|
|
|
|
"""
|
|
|
|
|
Mount user resource with waiting if need
|
|
|
|
|
"""
|
|
|
|
|
for waittime in [0.5,2,5]:
|
|
|
|
|
if self.mountSambaRes(host,self.userName,userPwd,
|
|
|
|
|
self.uid,self.gid,res,rpath) is False:
|
|
|
|
|
# check on mount path
|
|
|
|
|
if isMount(rpath):
|
|
|
|
|
if not self.umountSleepPath(rpath):
|
|
|
|
|
return False
|
|
|
|
|
# wait
|
|
|
|
|
time.sleep(waittime)
|
|
|
|
|
else:
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def copyTemplateDir(self, srcDir, destDir):
|
|
|
|
|
"""
|
|
|
|
|
Move directory srcDir to destDir
|
|
|
|
|
"""
|
|
|
|
|
if os.system("mv %s %s &>/dev/null"%(srcDir, destDir)) != 0:
|
|
|
|
|
raise ClientError(_("Failed to move %s")%srcDir + " " +\
|
|
|
|
|
_("to %s")%destDir)
|
|
|
|
|
|
|
|
|
|
def upgradeUserProfile(self, userName, userHome, pathTemplates):
|
|
|
|
|
"""
|
|
|
|
|
Update user profile (example /home/.user/.CLD to /home/.user/CLD)
|
|
|
|
|
"""
|
|
|
|
|
# directory which keop old profile
|
|
|
|
|
home = os.path.split(userHome)[0]
|
|
|
|
|
if os.path.exists(pathTemplates):
|
|
|
|
|
if self.clVars.Get("cl_profile_all_set") == "on":
|
|
|
|
|
osLinuxShort = "all"
|
|
|
|
|
else:
|
|
|
|
|
osLinuxShort = self.clVars.Get("os_linux_shortname")
|
|
|
|
|
pathNewTemplate = os.path.join(pathTemplates, osLinuxShort)
|
|
|
|
|
pathOldTemplate = os.path.join(pathTemplates, "."+osLinuxShort)
|
|
|
|
|
if not os.path.exists(pathNewTemplate) and\
|
|
|
|
|
os.path.exists(pathOldTemplate) and\
|
|
|
|
|
os.listdir(pathOldTemplate):
|
|
|
|
|
# move profile
|
|
|
|
|
self.copyTemplateDir(pathOldTemplate,pathNewTemplate)
|
|
|
|
|
if not os.path.exists(pathNewTemplate):
|
|
|
|
|
# create directory for profile keeping
|
|
|
|
|
os.mkdir(pathNewTemplate)
|
|
|
|
|
os.chmod(pathNewTemplate, 0700)
|
|
|
|
|
if os.path.exists(pathOldTemplate) and\
|
|
|
|
|
not os.listdir(pathOldTemplate):
|
|
|
|
|
os.rmdir(pathOldTemplate)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def syncUser(self, userName, userHome, sync, homeTemplate, \
|
|
|
|
|
host="default"):
|
|
|
|
|
"""
|
|
|
|
|
Sync user profile from server or to server
|
|
|
|
|
"""
|
|
|
|
|
flagError = False
|
|
|
|
|
execStr = ""
|
|
|
|
|
skipPaths = self.clVars.Get("cl_sync_skip_path")
|
|
|
|
|
if not skipPaths:
|
|
|
|
|
self.printERROR(
|
|
|
|
|
_("The variable 'cl_sync_skip_path' is empty")%userHome)
|
|
|
|
|
return False
|
|
|
|
|
deletePaths = self.clVars.Get("cl_sync_del_path")
|
|
|
|
|
if not deletePaths:
|
|
|
|
|
deletePaths = []
|
|
|
|
|
excludePaths = " ".join(map(lambda x: '--exclude="/%s"'\
|
|
|
|
|
%x.replace('"',"").replace("'",""),
|
|
|
|
|
skipPaths + deletePaths))
|
|
|
|
|
if sync == "login":
|
|
|
|
|
if os.path.exists(userHome) and\
|
|
|
|
|
os.path.exists(homeTemplate):
|
|
|
|
|
filterPath = " ".join(map(lambda x: '--filter="P /%s"'\
|
|
|
|
|
%x.replace('"',"").replace("'",""),
|
|
|
|
|
skipPaths))
|
|
|
|
|
execStr = '/usr/bin/rsync --delete-excluded --delete %s %s '\
|
|
|
|
|
'-rlptgo -x -v -v -v %s/ %s/' \
|
|
|
|
|
%(excludePaths, filterPath, homeTemplate, userHome)
|
|
|
|
|
elif sync == "logout":
|
|
|
|
|
if os.path.exists(userHome) and os.listdir(userHome) and\
|
|
|
|
|
os.path.exists(homeTemplate):
|
|
|
|
|
execStr = '/usr/bin/rsync --delete-excluded --delete %s \
|
|
|
|
|
-rlptgo -x -v -v -v %s/ %s/'%(excludePaths, userHome, homeTemplate)
|
|
|
|
|
else:
|
|
|
|
|
raise ClientError(
|
|
|
|
|
_("Method syncUser: option sync=%s incorrect")%str(sync))
|
|
|
|
|
if execStr:
|
|
|
|
|
host = "<i>" + host +"</i>"
|
|
|
|
|
if sync == "login":
|
|
|
|
|
rsync = RsyncProgressBar(\
|
|
|
|
|
_("Receiving the file list from %s") % host,
|
|
|
|
|
_("Downloading the user profile from %s") % host,
|
|
|
|
|
execStr,self)
|
|
|
|
|
else:
|
|
|
|
|
rsync = RsyncProgressBar(\
|
|
|
|
|
_("Sending the file list to %s") % host,
|
|
|
|
|
_("Uploading the user profile to %s") % host,
|
|
|
|
|
execStr,self)
|
|
|
|
|
pathConfig = os.path.join(homeTemplate,
|
|
|
|
|
self.pathConfig)
|
|
|
|
|
# remove old ini file
|
|
|
|
|
prevIniFile = os.path.join(homeTemplate,".calculate.ini")
|
|
|
|
|
if os.path.exists(prevIniFile):
|
|
|
|
|
os.remove(prevIniFile)
|
|
|
|
|
# create home directory
|
|
|
|
|
if not os.path.exists(pathConfig):
|
|
|
|
|
self.createUserDirectory(pathConfig)
|
|
|
|
|
numfiles = 0
|
|
|
|
|
configFileName = os.path.join(homeTemplate, self.configFileDesktop)
|
|
|
|
|
if sync == "login":
|
|
|
|
|
# get rsync files
|
|
|
|
|
try:
|
|
|
|
|
numfiles = \
|
|
|
|
|
iniParser(configFileName).getVar('rsync','files')
|
|
|
|
|
if numfiles is False:
|
|
|
|
|
if os.path.exists(configFileName):
|
|
|
|
|
os.remove(configFileName)
|
|
|
|
|
numfiles = 0
|
|
|
|
|
else:
|
|
|
|
|
numfiles = int(numfiles)
|
|
|
|
|
except:
|
|
|
|
|
numfiles = 0
|
|
|
|
|
rsync.maximum = numfiles
|
|
|
|
|
if sync == "login":
|
|
|
|
|
rsync.run()
|
|
|
|
|
if sync == "logout":
|
|
|
|
|
rsync.run()
|
|
|
|
|
try:
|
|
|
|
|
if iniParser(configFileName).setVar('rsync',
|
|
|
|
|
{'files':rsync.getFilesNum()}):
|
|
|
|
|
os.chmod(configFileName, 0600)
|
|
|
|
|
os.chown(configFileName,self.uid,self.gid)
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
rsync.close()
|
|
|
|
|
if rsync.getExitCode() != 0:
|
|
|
|
|
try:
|
|
|
|
|
if iniParser(configFileName).setVar(\
|
|
|
|
|
'rsync',{'exitcode':rsync.getExitCode()}):
|
|
|
|
|
os.chmod(configFileName, 0600)
|
|
|
|
|
os.chown(configFileName,self.uid,self.gid)
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
self.printERROR(rsync.getErrMessage())
|
|
|
|
|
self.printERROR(_("Failed to execute rsync") + " " + \
|
|
|
|
|
str(sync) + " ...")
|
|
|
|
|
return False
|
|
|
|
|
# change permissions
|
|
|
|
|
changeDirs = [userHome, homeTemplate]
|
|
|
|
|
for changeDir in changeDirs:
|
|
|
|
|
# get directory permissions
|
|
|
|
|
mode = getModeFile(changeDir, mode="mode")
|
|
|
|
|
# if permission wrong( not 0700) then change it
|
|
|
|
|
if mode != 0700:
|
|
|
|
|
os.chmod(changeDir,0700)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def clearHomeDir(self, homeDir):
|
|
|
|
|
"""Clear home directory"""
|
|
|
|
|
rmFiles = list(set(os.listdir(homeDir))-\
|
|
|
|
|
set(self.skipHomeFile))
|
|
|
|
|
for rmFile in rmFiles:
|
|
|
|
|
delFile = os.path.join(homeDir,rmFile)
|
|
|
|
|
if os.path.islink(delFile):
|
|
|
|
|
os.unlink(delFile)
|
|
|
|
|
elif os.path.isfile(delFile):
|
|
|
|
|
os.remove(delFile)
|
|
|
|
|
elif os.path.isdir(delFile):
|
|
|
|
|
if not removeDir(delFile):
|
|
|
|
|
return False
|
|
|
|
|
elif stat.S_ISSOCK(os.stat(delFile)[stat.ST_MODE]):
|
|
|
|
|
os.remove(delFile)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def syncLoginProfile(self, host, homeDir, homeProfile,
|
|
|
|
|
flagClearHomeDir=True):
|
|
|
|
|
"""
|
|
|
|
|
Get user profile from server
|
|
|
|
|
"""
|
|
|
|
|
# if currect server has any files then sync it
|
|
|
|
|
if filter(lambda x: not x in ('.calculate',), os.listdir(homeProfile)):
|
|
|
|
|
if not self.syncUser(self.userName, homeDir, "login",
|
|
|
|
|
homeProfile, host=host):
|
|
|
|
|
return False
|
|
|
|
|
# remove home directory on workstation
|
|
|
|
|
else:
|
|
|
|
|
if flagClearHomeDir:
|
|
|
|
|
# clean home directory
|
|
|
|
|
if not self.clearHomeDir(homeDir):
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def getDataInConfig(self, section, listVars, objConfig):
|
|
|
|
|
"""
|
|
|
|
|
Read variables listVars from section in configuration file
|
|
|
|
|
"""
|
|
|
|
|
varsConfig = {}
|
|
|
|
|
for varName in listVars:
|
|
|
|
|
varsConfig[varName] = objConfig.getVar(section,varName)
|
|
|
|
|
if objConfig.getError():
|
|
|
|
|
return False
|
|
|
|
|
return varsConfig
|
|
|
|
|
|
|
|
|
|
def foundArchFile(self,strCurrentTime,archPathProcess,
|
|
|
|
|
archPathSuccess, remoteServer=False):
|
|
|
|
|
"""Found user profile archive"""
|
|
|
|
|
self.startTask(_("Packing the archive on the server"),
|
|
|
|
|
progress=True)
|
|
|
|
|
for sleeptime in [0.1,0.2,0.5]:
|
|
|
|
|
# archive in packing process found
|
|
|
|
|
if os.path.exists(archPathProcess) or \
|
|
|
|
|
os.path.exists(archPathSuccess):
|
|
|
|
|
break
|
|
|
|
|
time.sleep(sleeptime)
|
|
|
|
|
else:
|
|
|
|
|
# archive not found
|
|
|
|
|
self.endTask(False)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
# wait finish packing
|
|
|
|
|
if os.path.exists(archPathProcess) or \
|
|
|
|
|
os.path.exists(archPathSuccess):
|
|
|
|
|
while os.path.exists(archPathProcess) or \
|
|
|
|
|
os.path.exists(archPathSuccess):
|
|
|
|
|
for waittime in [0.5,1,2]:
|
|
|
|
|
if os.path.exists(archPathSuccess):
|
|
|
|
|
self.endTask()
|
|
|
|
|
return True
|
|
|
|
|
try:
|
|
|
|
|
startSize = os.stat(archPathProcess).st_size
|
|
|
|
|
time.sleep(waittime)
|
|
|
|
|
if startSize != os.stat(archPathProcess).st_size:
|
|
|
|
|
break
|
|
|
|
|
except OSError as e:
|
|
|
|
|
if os.path.exists(archPathSuccess):
|
|
|
|
|
self.endTask()
|
|
|
|
|
return True
|
|
|
|
|
# run out of time size change
|
|
|
|
|
else:
|
|
|
|
|
# archive size was not change above 4s => archive not found
|
|
|
|
|
self.endTask(False)
|
|
|
|
|
return False
|
|
|
|
|
self.endTask(False)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def fileReader(self, fileName, stdin, maxSize):
|
|
|
|
|
"""
|
|
|
|
|
Read file by block
|
|
|
|
|
"""
|
|
|
|
|
fd = os.open(fileName, os.O_RDONLY)
|
|
|
|
|
currSize = 0
|
|
|
|
|
# default buffer size
|
|
|
|
|
buffSize=131072
|
|
|
|
|
dataBlock = os.read(fd, buffSize)
|
|
|
|
|
while dataBlock:
|
|
|
|
|
currSize += len(dataBlock)
|
|
|
|
|
self.setProgress(currSize*100/maxSize)
|
|
|
|
|
stdin.write(dataBlock)
|
|
|
|
|
dataBlock = os.read(fd, buffSize)
|
|
|
|
|
stdin.close()
|
|
|
|
|
os.close(fd)
|
|
|
|
|
|
|
|
|
|
def moveArch(self, srcArchFile, dstArchFile, remoteServer=False, mode=0600):
|
|
|
|
|
"""
|
|
|
|
|
Move archive from one directory to other
|
|
|
|
|
"""
|
|
|
|
|
class copyTo(color_print):
|
|
|
|
|
def __init__(self, destFile):
|
|
|
|
|
self.FD = open(destFile, "w")
|
|
|
|
|
os.chmod(destFile, mode)
|
|
|
|
|
def write(self, data):
|
|
|
|
|
self.FD.write(data)
|
|
|
|
|
def close(self):
|
|
|
|
|
self.FD.close()
|
|
|
|
|
try:
|
|
|
|
|
copyToObj = copyTo(dstArchFile)
|
|
|
|
|
except:
|
|
|
|
|
raise ClientError(_("Failed to create file '%s'")%dstArchFile)
|
|
|
|
|
archiveSize = os.stat(srcArchFile).st_size or 1
|
|
|
|
|
try:
|
|
|
|
|
self.fileReader(srcArchFile, copyToObj, archiveSize)
|
|
|
|
|
except:
|
|
|
|
|
raise ClientError(_("Failed to copy '%(from)s' -> '%(to)s'")\
|
|
|
|
|
%{'from':srcArchFile,
|
|
|
|
|
'to':dstArchFile})
|
|
|
|
|
|
|
|
|
|
def unpackArch(self, homeDir, archFile, remoteServer=False):
|
|
|
|
|
"""
|
|
|
|
|
Unpack archive into user home directory
|
|
|
|
|
"""
|
|
|
|
|
archiveSize = os.stat(archFile).st_size
|
|
|
|
|
execStr = "tar -C '%s' -xzf -" %homeDir
|
|
|
|
|
# run unpacking process
|
|
|
|
|
pipe = subprocess.Popen(execStr,
|
|
|
|
|
stdin=subprocess.PIPE,
|
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
|
close_fds=True,
|
|
|
|
|
env=os.environ, shell=True)
|
|
|
|
|
# read file into pipe
|
|
|
|
|
self.fileReader(archFile, pipe.stdin,archiveSize)
|
|
|
|
|
ret = pipe.wait()
|
|
|
|
|
pipe.stdout.close()
|
|
|
|
|
pipe.stderr.close()
|
|
|
|
|
if ret:
|
|
|
|
|
self.printWARNING(_("Failed to execute %s") %execStr)
|
|
|
|
|
self.printWARNING(_("Failed to unpack %s") %archFile)
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def setVarToConfig(self, nameSection, varsDict, configFileName):
|
|
|
|
|
"""Записывает переменную в файл конфигурации"""
|
|
|
|
|
# Создаем директорию для конфигурационных файлов
|
|
|
|
|
pathConfig = os.path.split(configFileName)[0]
|
|
|
|
|
if not os.path.exists(pathConfig):
|
|
|
|
|
self.createUserDirectory(pathConfig)
|
|
|
|
|
try:
|
|
|
|
|
if iniParser(configFileName).setVar(nameSection, varsDict):
|
|
|
|
|
os.chmod(configFileName, 0600)
|
|
|
|
|
os.chown(configFileName,self.uid,self.gid)
|
|
|
|
|
except:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def convertDate(self,strdate,dateformat="%Y-%m-%d %H:%M:%S"):
|
|
|
|
|
"""
|
|
|
|
|
Convert date from string format (dateformat) to stuct or None
|
|
|
|
|
"""
|
|
|
|
|
if strdate:
|
|
|
|
|
try:
|
|
|
|
|
return time.strptime(strdate,dateformat)
|
|
|
|
|
except ValueError:
|
|
|
|
|
pass
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def getDateObjClientConf(self, fileConfig):
|
|
|
|
|
"""
|
|
|
|
|
Return time object from config file .calculate/desktop.env
|
|
|
|
|
"""
|
|
|
|
|
if os.path.exists(fileConfig):
|
|
|
|
|
objConfig = iniParser(fileConfig)
|
|
|
|
|
data = self.getDataInConfig("main", ["date", "date_logout"],
|
|
|
|
|
objConfig)
|
|
|
|
|
timeLogout = data["date_logout"]
|
|
|
|
|
timeConfig = data["date"]
|
|
|
|
|
dates = filter(None,
|
|
|
|
|
[self.convertDate(timeLogout),
|
|
|
|
|
self.convertDate(timeConfig)])
|
|
|
|
|
if dates:
|
|
|
|
|
return dates[0]
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def createUserDirectory(self,userdir):
|
|
|
|
|
"""
|
|
|
|
|
Create directory with user permissions
|
|
|
|
|
"""
|
|
|
|
|
if not os.path.exists(userdir):
|
|
|
|
|
try:
|
|
|
|
|
os.mkdir(userdir)
|
|
|
|
|
os.chown(userdir, self.uid, self.gid)
|
|
|
|
|
os.chmod(userdir,0700)
|
|
|
|
|
except OSError:
|
|
|
|
|
raise ClientError(_("Error creating the directory")+
|
|
|
|
|
_("Permission denied: '%s'")%userdir)
|
|
|
|
|
|
|
|
|
|
def checkNeedSync(self,rpath,curTimeObj,curStatusSync,osLinuxShort):
|
|
|
|
|
"""
|
|
|
|
|
Check about need sync with domain profile by profile time
|
|
|
|
|
"""
|
|
|
|
|
# upgrade user profile or create need profile directory
|
|
|
|
|
self.upgradeUserProfile(self.userName, self.homeDir, rpath)
|
|
|
|
|
# profile directory
|
|
|
|
|
pathProfile = os.path.join(rpath, osLinuxShort)
|
|
|
|
|
fileSoftConfigThis = os.path.join(pathProfile,
|
|
|
|
|
self.configFileSoft)
|
|
|
|
|
fileSoftConfigCur = os.path.join(self.homeDir,
|
|
|
|
|
self.configFileSoft)
|
|
|
|
|
xSessionCur = iniParser(fileSoftConfigCur).getVar('main','xsession')
|
|
|
|
|
xSessionThis = iniParser(fileSoftConfigThis).getVar('main','xsession')
|
|
|
|
|
# check profile date on current server
|
|
|
|
|
fileConfigThis = os.path.join(pathProfile,
|
|
|
|
|
self.configFileDesktop)
|
|
|
|
|
if iniParser(fileConfigThis).getVar('main','status_sync') == "success":
|
|
|
|
|
self.setVarToConfig("main", {"status_sync":"success_mount"},
|
|
|
|
|
fileConfigThis)
|
|
|
|
|
thisTimeObj = self.getDateObjClientConf(fileConfigThis)
|
|
|
|
|
if curStatusSync == "success_logout" and \
|
|
|
|
|
xSessionCur == xSessionThis and \
|
|
|
|
|
thisTimeObj and curTimeObj and \
|
|
|
|
|
curTimeObj >= thisTimeObj:
|
|
|
|
|
return False,pathProfile
|
|
|
|
|
return True,pathProfile
|
|
|
|
|
|
|
|
|
|
def mountLocalDomainRes(self,userPwd,dictRes):
|
|
|
|
|
"""
|
|
|
|
|
Mount all local samba resource
|
|
|
|
|
"""
|
|
|
|
|
res = True
|
|
|
|
|
configFileName = os.path.join(self.homeDir, self.configFileDesktop)
|
|
|
|
|
for name in dictRes.keys():
|
|
|
|
|
if name == "remote_profile":
|
|
|
|
|
continue
|
|
|
|
|
rpath = dictRes[name]["path"]
|
|
|
|
|
res = dictRes[name]["resource"]
|
|
|
|
|
# create user directory
|
|
|
|
|
self.createUserDirectory(rpath)
|
|
|
|
|
# is directory already mount
|
|
|
|
|
if isMount(rpath):
|
|
|
|
|
continue
|
|
|
|
|
else:
|
|
|
|
|
if self.mountSleepRes(self.domain, userPwd,
|
|
|
|
|
res, rpath) is False:
|
|
|
|
|
if name == "profile":
|
|
|
|
|
self.printWARNING(_("Failed to mount user profile"))
|
|
|
|
|
res = False
|
|
|
|
|
continue
|
|
|
|
|
else:
|
|
|
|
|
raise ClientError(
|
|
|
|
|
_("Failed to mount Samba resource [%s]")%res)
|
|
|
|
|
elif name == "profile":
|
|
|
|
|
# upgrade user profile or create need profile directory
|
|
|
|
|
self.upgradeUserProfile(self.userName, self.homeDir, rpath)
|
|
|
|
|
else:
|
|
|
|
|
return res
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def syncLocalDomainRes(self,userPwd,dictRes,curTimeObj,curStatusSync,
|
|
|
|
|
osLinuxShort,fromRemote=False):
|
|
|
|
|
"""
|
|
|
|
|
Sync profile with current server
|
|
|
|
|
|
|
|
|
|
fromRemote - method called by remote sync method
|
|
|
|
|
"""
|
|
|
|
|
if self.mountLocalDomainRes(userPwd,dictRes):
|
|
|
|
|
if not self.sync: return True
|
|
|
|
|
if "profile" in dictRes:
|
|
|
|
|
rpath = dictRes["profile"]["path"]
|
|
|
|
|
needSync,lDomainProfile = self.checkNeedSync(rpath, curTimeObj,
|
|
|
|
|
curStatusSync,osLinuxShort)
|
|
|
|
|
if not needSync:
|
|
|
|
|
if fromRemote:
|
|
|
|
|
self.printSUCCESS(_("Local user profile does not need "
|
|
|
|
|
"to update with local domain"))
|
|
|
|
|
else:
|
|
|
|
|
self.printSUCCESS(_("Local user profile will be used"))
|
|
|
|
|
# Copy private files from the server
|
|
|
|
|
self.copyPrivateFiles(lDomainProfile, self.homeDir)
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
# sync profile with current server
|
|
|
|
|
return self.syncLoginProfile(self.domain,self.homeDir,
|
|
|
|
|
lDomainProfile)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _getRemoteServerProfileByArch(self,dictRes,rHomeProfile,
|
|
|
|
|
dateDefaultTemplate,userPwd,curTimeObj,
|
|
|
|
|
curStatusSync,remoteServer,
|
|
|
|
|
osLinuxShort):
|
|
|
|
|
"""
|
|
|
|
|
Try get profile from remote server
|
|
|
|
|
"""
|
|
|
|
|
# current time
|
|
|
|
|
currTime = str(float(time.time()))
|
|
|
|
|
archPathSuccess,archPathProcess,archPathSrc,archPathDst = \
|
|
|
|
|
(None,None,None,None)
|
|
|
|
|
try:
|
|
|
|
|
rpath = dictRes["remote_profile"]["path"]
|
|
|
|
|
res = dictRes["remote_profile"]["resource"]
|
|
|
|
|
# create command for create incremental arch
|
|
|
|
|
fileConfig = \
|
|
|
|
|
os.path.join(rHomeProfile,self.configFileServer)
|
|
|
|
|
varsConfig = {"arch_date":dateDefaultTemplate,
|
|
|
|
|
"curr_time":currTime}
|
|
|
|
|
try:
|
|
|
|
|
self.setServerCommand(["pack"], varsConfig, fileConfig)
|
|
|
|
|
except ClientError as e:
|
|
|
|
|
return False
|
|
|
|
|
rFileConfig = os.path.join(rHomeProfile, self.configFileDesktop)
|
|
|
|
|
self.setVarToConfig("main", {"status_sync":"success"},
|
|
|
|
|
rFileConfig)
|
|
|
|
|
self.umountSleepPath(rpath)
|
|
|
|
|
|
|
|
|
|
if not self.syncLocalDomainRes(userPwd,dictRes,curTimeObj,
|
|
|
|
|
curStatusSync,osLinuxShort,
|
|
|
|
|
fromRemote=True):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
if self.mountSleepRes(remoteServer, userPwd, res, rpath) is False:
|
|
|
|
|
return False
|
|
|
|
|
self.setVarToConfig("main", {"status_sync":"success_mount"},
|
|
|
|
|
rFileConfig)
|
|
|
|
|
extSuccess = "gz"
|
|
|
|
|
extProcess = "process"
|
|
|
|
|
strCurrentTime = currTime.replace(".","_")
|
|
|
|
|
archPathTmp = os.path.join(rpath, "profile.%s.%s.tar"\
|
|
|
|
|
%(osLinuxShort, strCurrentTime))
|
|
|
|
|
# result archive file name
|
|
|
|
|
archPathSuccess = "%s.%s"%(archPathTmp,extSuccess)
|
|
|
|
|
# archive in pack process
|
|
|
|
|
archPathProcess = "%s.%s"%(archPathTmp,extProcess)
|
|
|
|
|
# find archive file
|
|
|
|
|
if not self.foundArchFile(strCurrentTime, archPathProcess,
|
|
|
|
|
archPathSuccess,
|
|
|
|
|
remoteServer):
|
|
|
|
|
self.printWARNING(_("Failed to find profile archive from %s")%
|
|
|
|
|
remoteServer)
|
|
|
|
|
return False
|
|
|
|
|
if os.path.exists(archPathSuccess):
|
|
|
|
|
archPathSrc = archPathSuccess
|
|
|
|
|
archPathDst = ".".join(filter(lambda x: x!="/",
|
|
|
|
|
archPathSuccess.rpartition("/")))
|
|
|
|
|
# get archive
|
|
|
|
|
self.startTask(_("Copying archive from the server"),
|
|
|
|
|
progress=True)
|
|
|
|
|
try:
|
|
|
|
|
self.moveArch(archPathSrc, archPathDst,
|
|
|
|
|
remoteServer)
|
|
|
|
|
except ClientError as e:
|
|
|
|
|
self.printWARNING(str(e))
|
|
|
|
|
return False
|
|
|
|
|
self.endTask()
|
|
|
|
|
# unpack archive into home directory
|
|
|
|
|
self.startTask(_("Unpack profile archive"),progress=True)
|
|
|
|
|
if not self.unpackArch(self.homeDir, archPathDst,
|
|
|
|
|
remoteServer):
|
|
|
|
|
self.printERROR(_("Failed to unpack archive"))
|
|
|
|
|
return False
|
|
|
|
|
# get removed files list
|
|
|
|
|
pathListFile = os.path.join(rHomeProfile,
|
|
|
|
|
self.listTemplFile)
|
|
|
|
|
if not self.removeFilesInProfile(self.homeDir,pathListFile):
|
|
|
|
|
self.printWARNING(_("Unable to remove needless files"))
|
|
|
|
|
return False
|
|
|
|
|
self.endTask()
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
finally:
|
|
|
|
|
for rmFile in (archPathSuccess,archPathProcess,
|
|
|
|
|
archPathSrc,archPathDst):
|
|
|
|
|
if rmFile and os.path.exists(rmFile):
|
|
|
|
|
os.remove(rmFile)
|
|
|
|
|
|
|
|
|
|
def syncRemoteDomainRes(self,userPwd,dictRes,remoteServer,curTimeObj,
|
|
|
|
|
curStatusSync,osLinuxShort):
|
|
|
|
|
"""
|
|
|
|
|
Sync if actual profile is kept on a remote server
|
|
|
|
|
"""
|
|
|
|
|
# mount directories path
|
|
|
|
|
if not "remote_profile" in dictRes:
|
|
|
|
|
return False
|
|
|
|
|
if not self.sync:
|
|
|
|
|
self.mountLocalDomainRes(userPwd,dictRes)
|
|
|
|
|
return True
|
|
|
|
|
rpath = dictRes["remote_profile"]["path"]
|
|
|
|
|
res = dictRes["remote_profile"]["resource"]
|
|
|
|
|
# create user directory
|
|
|
|
|
self.createUserDirectory(rpath)
|
|
|
|
|
# mount remote profile
|
|
|
|
|
if isMount(rpath):
|
|
|
|
|
self.printWARNING(_("Remote profile already mounted"))
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
if self.mountSleepRes(remoteServer, userPwd, res, rpath) is False:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
rpath = dictRes["remote_profile"]["path"]
|
|
|
|
|
needSync,pathRProfile = self.checkNeedSync(rpath,curTimeObj,
|
|
|
|
|
curStatusSync,osLinuxShort)
|
|
|
|
|
if not needSync:
|
|
|
|
|
# Copy private files from the server
|
|
|
|
|
self.printSUCCESS(_("Local user profile will be used"))
|
|
|
|
|
if not self.mountLocalDomainRes(userPwd,dictRes):
|
|
|
|
|
return False
|
|
|
|
|
self.copyPrivateFiles(pathRProfile, self.homeDir)
|
|
|
|
|
return True
|
|
|
|
|
localServer = self.domain
|
|
|
|
|
# mount local samba resources
|
|
|
|
|
if self.mountLocalDomainRes(userPwd,dictRes):
|
|
|
|
|
lpath = dictRes["profile"]["path"]
|
|
|
|
|
homeLProfile = os.path.join(lpath, osLinuxShort)
|
|
|
|
|
if not os.path.exists(homeLProfile):
|
|
|
|
|
homeLProfile = os.path.join(lpath, "." + osLinuxShort)
|
|
|
|
|
lFileConfig = os.path.join(homeLProfile, self.configFileDesktop)
|
|
|
|
|
# get data from desktop config on success run get by archive
|
|
|
|
|
if os.path.exists(lFileConfig):
|
|
|
|
|
objConfig = iniParser(lFileConfig)
|
|
|
|
|
data = self.getDataInConfig("main", ["status_sync",
|
|
|
|
|
"date","date_logout"],
|
|
|
|
|
objConfig)
|
|
|
|
|
if data:
|
|
|
|
|
status = data.get("status_sync")
|
|
|
|
|
date = data.get("date")
|
|
|
|
|
date_logout = data.get("date_logout")
|
|
|
|
|
if date and date_logout:
|
|
|
|
|
diffdate = \
|
|
|
|
|
abs(time.mktime(self.convertDate(date))-
|
|
|
|
|
time.mktime(self.convertDate(date_logout)))
|
|
|
|
|
else:
|
|
|
|
|
diffdate = None
|
|
|
|
|
# if diff date less 10 min
|
|
|
|
|
if diffdate is None or diffdate < 600:
|
|
|
|
|
if date and "success" in status:
|
|
|
|
|
if self._getRemoteServerProfileByArch(dictRes,
|
|
|
|
|
pathRProfile,date,userPwd,
|
|
|
|
|
curTimeObj, curStatusSync,
|
|
|
|
|
remoteServer, osLinuxShort):
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
self.printWARNING(
|
|
|
|
|
_("Difference time between server and "
|
|
|
|
|
"client more 10 minute"))
|
|
|
|
|
self.printWARNING(_("Profile synchronization "
|
|
|
|
|
"will be used without archiving"))
|
|
|
|
|
# sync local before remote sync
|
|
|
|
|
self.syncLocalDomainRes(userPwd,dictRes,curTimeObj,
|
|
|
|
|
curStatusSync,osLinuxShort,
|
|
|
|
|
fromRemote=True)
|
|
|
|
|
# get user profile from remote domain
|
|
|
|
|
return self.syncLoginProfile(remoteServer, self.homeDir,
|
|
|
|
|
pathRProfile, False)
|
|
|
|
|
finally:
|
|
|
|
|
# unmount remote profile
|
|
|
|
|
if self.sync and "remote_profile" in dictRes:
|
|
|
|
|
if isMount(rpath):
|
|
|
|
|
if not self.umountSleepPath(rpath):
|
|
|
|
|
raise ClientError(_("Failed to unmount remote profile"))
|
|
|
|
|
# remote directory for remote
|
|
|
|
|
if os.path.exists(rpath) and not os.listdir(rpath):
|
|
|
|
|
os.rmdir(rpath)
|
|
|
|
|
|
|
|
|
|
def errorUmountUserRes(self,error):
|
|
|
|
|
"""
|
|
|
|
|
Post action for umount user res and write status_sync=error
|
|
|
|
|
"""
|
|
|
|
|
self.closeClTemplate()
|
|
|
|
|
if error and self.homeDir:
|
|
|
|
|
umountResult = self.umountUserRes(self.homeDir)
|
|
|
|
|
configFileName = os.path.join(self.homeDir, self.configFileDesktop)
|
|
|
|
|
uid = self.clVars.Get('ur_uid')
|
|
|
|
|
gid = self.clVars.Get('ur_gid')
|
|
|
|
|
self.setVarToConfig("main", {"status_sync":"error"},
|
|
|
|
|
configFileName)
|
|
|
|
|
self.printERROR(_("Failed to get user profile from domain"))
|
|
|
|
|
return umountResult
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# def postAct(self,error):
|
|
|
|
|
# """
|
|
|
|
|
# Post action for umount user res and write status_sync=error
|
|
|
|
|
# """
|
|
|
|
|
# self.printSUCCESS("OK")
|
|
|
|
|
# return True
|
|
|
|
|
#
|
|
|
|
|
# @safetyWrapper(native_errors=(TemplatesError,ClientError),
|
|
|
|
|
# man_int=__("Manually interrupted"),
|
|
|
|
|
# post_action=postAct)
|
|
|
|
|
# def clienttest(self,dv):
|
|
|
|
|
# import time
|
|
|
|
|
# self.initVars(dv)
|
|
|
|
|
# self.startTask("Hello",progress=True)
|
|
|
|
|
# time.sleep(2)
|
|
|
|
|
# self.endTask()
|
|
|
|
|
# self.startTask("ZXC",progress=True)
|
|
|
|
|
# time.sleep(1)
|
|
|
|
|
# self.setProgress(33)
|
|
|
|
|
# time.sleep(1)
|
|
|
|
|
# self.setProgress(66)
|
|
|
|
|
# self.printWARNING("BAD")
|
|
|
|
|
# self.printWARNING("BAD")
|
|
|
|
|
# #raise ClientError("Hello world")
|
|
|
|
|
# #z = 5 / 0
|
|
|
|
|
# self.printWARNING("BAD")
|
|
|
|
|
# self.printWARNING("BAD")
|
|
|
|
|
# time.sleep(1)
|
|
|
|
|
# self.setProgress(100)
|
|
|
|
|
# self.endTask()
|
|
|
|
|
# self.printSUCCESS("HELLO")
|
|
|
|
|
# return True
|
|
|
|
|
|
|
|
|
|
@safetyWrapper(native_errors=(TemplatesError,ClientError),
|
|
|
|
|
man_int=__("Manually interrupted"),
|
|
|
|
|
post_action=errorUmountUserRes)
|
|
|
|
|
def mountUserResAndSync(self,dv):
|
|
|
|
|
"""Mount user resources and sync profile"""
|
|
|
|
|
self.initVars(dv)
|
|
|
|
|
try:
|
|
|
|
|
self.uid = int(self.clVars.Get('ur_uid'))
|
|
|
|
|
self.gid = int(self.clVars.Get('ur_gid'))
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
raise ClientError(_("Failed to determnate UID and GID"))
|
|
|
|
|
self.sync = self.clVars.Get('cl_client_sync') == 'on'
|
|
|
|
|
self.userName = self.clVars.Get("ur_login")
|
|
|
|
|
self.homeDir = self.clVars.Get('ur_home_path')
|
|
|
|
|
self.domain = self.clVars.Get("cl_remote_host")
|
|
|
|
|
if self.domain:
|
|
|
|
|
foundMountRemote = isMount("/var/calculate/remote")
|
|
|
|
|
if not foundMountRemote:
|
|
|
|
|
self.mountRemote();
|
|
|
|
|
# check on two session user login
|
|
|
|
|
if self.isTwoSessionsUser(self.userName):
|
|
|
|
|
return False
|
|
|
|
|
hostAuth = self.clVars.Get("os_remote_auth")
|
|
|
|
|
|
|
|
|
|
# if not domain
|
|
|
|
|
if not hostAuth or not self.domain:
|
|
|
|
|
self.printSUCCESS(_("The local profile will be used"))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
passwdUsers = map(lambda x: x[0],
|
|
|
|
|
map(lambda x: x.split(':'),
|
|
|
|
|
map(lambda x: x.strip(),
|
|
|
|
|
open("/etc/passwd").readlines())))
|
|
|
|
|
except:
|
|
|
|
|
self.printERROR(_("Failed to open /etc/passwd"))
|
|
|
|
|
return False
|
|
|
|
|
if self.userName in passwdUsers:
|
|
|
|
|
try:
|
|
|
|
|
pwdObj = pwd.getpwnam(self.userName)
|
|
|
|
|
except:
|
|
|
|
|
raise ClientError(_("Failed to found user %s")%self.userName)
|
|
|
|
|
self.printWARNING(_("User information from /etc/passwd is used"))
|
|
|
|
|
return True
|
|
|
|
|
# check for domain workstation and [remote] was mounted
|
|
|
|
|
if not self.isDomain():
|
|
|
|
|
raise ClientError(_("The computer is not in the domain"))
|
|
|
|
|
# user config filename
|
|
|
|
|
configFileName = os.path.join(self.homeDir, self.configFileDesktop)
|
|
|
|
|
# user time object from config file
|
|
|
|
|
currentTimeObj = self.getDateObjClientConf(configFileName)
|
|
|
|
|
currentStatusSync = self.getSyncStatus(self.homeDir)
|
|
|
|
|
# create home directory if it is not exists
|
|
|
|
|
if not os.path.exists(self.homeDir):
|
|
|
|
|
os.makedirs(self.homeDir)
|
|
|
|
|
os.chown(self.homeDir,self.uid,self.gid)
|
|
|
|
|
os.chmod(self.homeDir,0700)
|
|
|
|
|
# get local date and statusSync
|
|
|
|
|
# write into config status "process"
|
|
|
|
|
self.setVarToConfig("main", {"status_sync":"process"}, configFileName)
|
|
|
|
|
# get user password from key kernel
|
|
|
|
|
userPwd = getKey(self.userName)
|
|
|
|
|
if not userPwd or userPwd == "XXXXXXXX":
|
|
|
|
|
raise ClientError(_("User password not found"))
|
|
|
|
|
# user cache
|
|
|
|
|
if not self.cAddUserToCache(self.userName, userPwd):
|
|
|
|
|
self.printWARNING(_("Unable cache user info"))
|
|
|
|
|
# profile name
|
|
|
|
|
if self.clVars.Get("cl_profile_all_set") == "on":
|
|
|
|
|
osLinuxShort = "all"
|
|
|
|
|
else:
|
|
|
|
|
osLinuxShort = self.clVars.Get("os_linux_shortname")
|
|
|
|
|
# if replication is on
|
|
|
|
|
replOn = self.ldapDataObj.isRepl()
|
|
|
|
|
# remote domain name
|
|
|
|
|
if replOn:
|
|
|
|
|
remoteServer = self.ldapDataObj.getNameRemoteServer(
|
|
|
|
|
self.userName, osLinuxShort, self.domain)
|
|
|
|
|
else:
|
|
|
|
|
remoteServer = ""
|
|
|
|
|
# get mount directory
|
|
|
|
|
dictRes = self.getUserMountResources(self.userName, self.homeDir,
|
|
|
|
|
remoteServer)
|
|
|
|
|
if isMount(dictRes["profile"]["path"]):
|
|
|
|
|
self.sync = False
|
|
|
|
|
useRemoteProfile = remoteServer and replOn
|
|
|
|
|
profileServer = self.domain
|
|
|
|
|
# if profile on remote server
|
|
|
|
|
if useRemoteProfile:
|
|
|
|
|
if not self.syncRemoteDomainRes(userPwd,dictRes,
|
|
|
|
|
remoteServer,currentTimeObj,
|
|
|
|
|
currentStatusSync,osLinuxShort):
|
|
|
|
|
syncStatus = "error"
|
|
|
|
|
useRemoteProfile = False
|
|
|
|
|
self.printWARNING(
|
|
|
|
|
_("Error synchronizing with the remote server %s")
|
|
|
|
|
%remoteServer)
|
|
|
|
|
else:
|
|
|
|
|
syncStatus = "success"
|
|
|
|
|
profileServer = remoteServer
|
|
|
|
|
# if profile not remote or remote sync is failed
|
|
|
|
|
if not useRemoteProfile:
|
|
|
|
|
if self.syncLocalDomainRes(userPwd,dictRes,currentTimeObj,
|
|
|
|
|
currentStatusSync,osLinuxShort):
|
|
|
|
|
# if not fallback for remote sync
|
|
|
|
|
if not(remoteServer and replOn):
|
|
|
|
|
syncStatus = "success"
|
|
|
|
|
else:
|
|
|
|
|
syncStatus = "error"
|
|
|
|
|
self.printWARNING(
|
|
|
|
|
_("Error synchronizing with the remote server %s")
|
|
|
|
|
%self.domain)
|
|
|
|
|
if self.sync:
|
|
|
|
|
self.setVarToConfig("main", {"status_sync":syncStatus},
|
|
|
|
|
configFileName)
|
|
|
|
|
# unpack link from link arch
|
|
|
|
|
self.unpackLinks(self.homeDir)
|
|
|
|
|
|
|
|
|
|
self.printSUCCESS(_("Mounted user resource of the domain"))
|
|
|
|
|
if self.sync:
|
|
|
|
|
if syncStatus == "error":
|
|
|
|
|
self.printWARNING(
|
|
|
|
|
_("Get a user fallback profile from the %s domain")
|
|
|
|
|
%profileServer)
|
|
|
|
|
else:
|
|
|
|
|
self.printSUCCESS(_("Get a user profile from the %s domain")%
|
|
|
|
|
profileServer)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def isSessionUser(self, userName):
|
|
|
|
|
"""
|
|
|
|
|
Check for user in X session
|
|
|
|
|
"""
|
|
|
|
|
reFoundUser = re.compile("%s\s+:\d+\s+"%(userName))
|
|
|
|
|
resWho = self.execProg("who")
|
|
|
|
|
if resWho:
|
|
|
|
|
if any(reFoundUser.search(x) for x in resWho):
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def tarSymLinks(self,userHome,uid,gid):
|
|
|
|
|
"""Create tar archive of symlinks"""
|
|
|
|
|
linkArch = pathJoin(userHome,".calculate/links.tar.bz2")
|
|
|
|
|
try:
|
|
|
|
|
for filename in tarLinks(userHome,linkArch,
|
|
|
|
|
skip=self.clVars.Get("cl_sync_del_path")+
|
|
|
|
|
self.clVars.Get("cl_sync_skip_path")):
|
|
|
|
|
try:
|
|
|
|
|
os.unlink(filename)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.printWARNING(_("Failed to remove %s")%filename)
|
|
|
|
|
except:
|
|
|
|
|
self.printWARNING(_("Failed to make links archive"))
|
|
|
|
|
try:
|
|
|
|
|
if os.path.exists(linkArch):
|
|
|
|
|
os.chown(linkArch,uid,gid)
|
|
|
|
|
except:
|
|
|
|
|
self.printWARNING(_("Failed to make links archive"))
|
|
|
|
|
|
|
|
|
|
def unpackLinks(self,userHome):
|
|
|
|
|
"""Unpack archive of symlinks"""
|
|
|
|
|
linksArch = pathJoin(userHome,".calculate/links.tar.bz2")
|
|
|
|
|
try:
|
|
|
|
|
if os.path.exists(linksArch):
|
|
|
|
|
tf = tarfile.open(linksArch)
|
|
|
|
|
tf.extractall(userHome)
|
|
|
|
|
tf.close()
|
|
|
|
|
except:
|
|
|
|
|
self.printWARNING(_("Failed to unpack links archive"))
|
|
|
|
|
|
|
|
|
|
def moveHomeDir(self, userHome):
|
|
|
|
|
"""
|
|
|
|
|
Move non profile files in root of home profile to Home/Moved
|
|
|
|
|
"""
|
|
|
|
|
pathProg = os.getcwd()
|
|
|
|
|
os.chdir(userHome)
|
|
|
|
|
dirs = []
|
|
|
|
|
files = []
|
|
|
|
|
movedLink = os.path.join('Moved')
|
|
|
|
|
movedPath = os.path.join('Home',"Moved")
|
|
|
|
|
skipPaths = self.clVars.Get("cl_moved_skip_path")
|
|
|
|
|
if not skipPaths:
|
|
|
|
|
skipPaths = ['Disks','Share','Home','Moved','FTP','Desktop']
|
|
|
|
|
filesAndDir = filter(lambda x: not ('.' in x[0] or x in\
|
|
|
|
|
skipPaths or os.path.islink(x)),
|
|
|
|
|
os.listdir('.'))
|
|
|
|
|
filesDir = []
|
|
|
|
|
for fd in filesAndDir:
|
|
|
|
|
if os.path.islink(fd):
|
|
|
|
|
os.unlink(fd)
|
|
|
|
|
else:
|
|
|
|
|
filesDir.append(fd)
|
|
|
|
|
# find files in Desktop
|
|
|
|
|
pathDesktop = './Desktop'
|
|
|
|
|
filesDirDesk = []
|
|
|
|
|
if os.path.exists(pathDesktop):
|
|
|
|
|
filesDirDesk = filter(lambda x: not os.path.islink(x) and\
|
|
|
|
|
not os.path.split(x)[1].startswith('.') and\
|
|
|
|
|
not x.rpartition('.')[2]=='desktop',
|
|
|
|
|
map(lambda x: os.path.join(pathDesktop,x),\
|
|
|
|
|
os.listdir(pathDesktop)))
|
|
|
|
|
movedPathDesk = os.path.join(movedPath, pathDesktop)
|
|
|
|
|
filesDir += filesDirDesk
|
|
|
|
|
if not filesDir or not os.path.exists("Home"):
|
|
|
|
|
# remote empty Moved folder
|
|
|
|
|
if os.path.exists(movedPath) and not os.listdir(movedPath):
|
|
|
|
|
os.rmdir(movedPath)
|
|
|
|
|
# remote link to Moved in home directory
|
|
|
|
|
if os.path.islink(movedLink) and not os.path.exists(movedPath):
|
|
|
|
|
os.unlink(movedLink)
|
|
|
|
|
return True
|
|
|
|
|
if not os.path.exists(movedPath):
|
|
|
|
|
os.mkdir(movedPath)
|
|
|
|
|
directFile = os.path.join(movedPath,".directory")
|
|
|
|
|
if not os.path.exists(directFile):
|
|
|
|
|
txt = "[Desktop Entry]\nIcon=folder-development"
|
|
|
|
|
fd = os.open(directFile, os.O_CREAT)
|
|
|
|
|
os.close(fd)
|
|
|
|
|
FD = open (directFile, "r+")
|
|
|
|
|
FD.write(txt)
|
|
|
|
|
FD.close()
|
|
|
|
|
if not os.path.exists(movedLink):
|
|
|
|
|
os.symlink(movedPath, movedLink)
|
|
|
|
|
for fd in filesDir:
|
|
|
|
|
execStr = "cp -r '%s' '%s'" %(fd, movedPath)
|
|
|
|
|
textLine = self.execProg(execStr)
|
|
|
|
|
if textLine is False:
|
|
|
|
|
self.printERROR(_("Failed to execute") + " " + str(execStr))
|
|
|
|
|
return False
|
|
|
|
|
execStr = "rm -rf '%s'" %fd
|
|
|
|
|
textLine = self.execProg(execStr)
|
|
|
|
|
if textLine is False:
|
|
|
|
|
self.printERROR(_("Failed to execute") + " " + str(execStr))
|
|
|
|
|
return False
|
|
|
|
|
os.chdir(pathProg)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def removeNoiseFiles(self, userHome):
|
|
|
|
|
"""
|
|
|
|
|
Remove files which hinder dm
|
|
|
|
|
"""
|
|
|
|
|
noiseFiles = []
|
|
|
|
|
for nsFile in noiseFiles:
|
|
|
|
|
rmFile = os.path.join(userHome, nsFile)
|
|
|
|
|
if os.path.exists(rmFile):
|
|
|
|
|
os.remove(rmFile)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def getPrivateFiles(self, userHome):
|
|
|
|
|
"""
|
|
|
|
|
Get all private files relative user home directory
|
|
|
|
|
"""
|
|
|
|
|
privateFiles = []
|
|
|
|
|
for privateHomeDir in self.privateDirs:
|
|
|
|
|
privateDir = os.path.join(userHome,privateHomeDir)
|
|
|
|
|
if os.path.isdir(privateDir):
|
|
|
|
|
# .ssh files relative user home directory
|
|
|
|
|
privateFiles += map(lambda x:os.path.join(privateHomeDir,x),
|
|
|
|
|
filter(lambda x:\
|
|
|
|
|
os.path.isfile(os.path.join(privateDir,x)),
|
|
|
|
|
os.listdir(privateDir)))
|
|
|
|
|
return self.privateFiles + privateFiles
|
|
|
|
|
|
|
|
|
|
def removePrivateFiles(self, userHome):
|
|
|
|
|
"""
|
|
|
|
|
Remove private files
|
|
|
|
|
"""
|
|
|
|
|
privateFiles = self.getPrivateFiles(userHome)
|
|
|
|
|
for prFile in privateFiles:
|
|
|
|
|
rmFile = os.path.join(userHome, prFile)
|
|
|
|
|
if os.path.exists(rmFile):
|
|
|
|
|
os.remove(rmFile)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def copyPrivateFiles(self, serverProfileDir, userHomeDir):
|
|
|
|
|
"""
|
|
|
|
|
Copy privates files from server to home directory
|
|
|
|
|
"""
|
|
|
|
|
privateFiles = self.getPrivateFiles(serverProfileDir)
|
|
|
|
|
for prFile in privateFiles:
|
|
|
|
|
src = os.path.join(serverProfileDir, prFile)
|
|
|
|
|
dst = os.path.join(userHomeDir, prFile)
|
|
|
|
|
if os.path.exists(src):
|
|
|
|
|
dstPath = os.path.dirname(dst)
|
|
|
|
|
if not os.path.exists(dstPath):
|
|
|
|
|
listElPath = []
|
|
|
|
|
for el in filter(lambda x: x,
|
|
|
|
|
dstPath.partition(userHomeDir)[2].split("/")):
|
|
|
|
|
listElPath.append(el)
|
|
|
|
|
joinPath = "/".join(listElPath)
|
|
|
|
|
dPath = os.path.join(userHomeDir, joinPath)
|
|
|
|
|
if not os.path.exists(dPath):
|
|
|
|
|
sPath = os.path.join(serverProfileDir, joinPath)
|
|
|
|
|
sMode, sUid, sGid = getModeFile(sPath)
|
|
|
|
|
os.mkdir(dPath,sMode)
|
|
|
|
|
os.chown(dPath, sUid, sGid)
|
|
|
|
|
copy2(src, dst)
|
|
|
|
|
sUid, sGid = getModeFile(src, mode="owner")
|
|
|
|
|
os.chown(dst, sUid, sGid)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def scanDirectory(self, scanDir, listFiles, skipPath=[], prefix=False,
|
|
|
|
|
flagDir=False):
|
|
|
|
|
"""
|
|
|
|
|
Generate file/directory list
|
|
|
|
|
"""
|
|
|
|
|
if not prefix:
|
|
|
|
|
prefix = os.path.join(scanDir,"")
|
|
|
|
|
if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
|
|
|
|
|
for fileOrDir in os.listdir(scanDir):
|
|
|
|
|
absPath = os.path.join(scanDir,fileOrDir)
|
|
|
|
|
relPath = absPath.split(prefix)[1]
|
|
|
|
|
if relPath in skipPath:
|
|
|
|
|
continue
|
|
|
|
|
listFiles.append(relPath)
|
|
|
|
|
stInfo = os.lstat(absPath)
|
|
|
|
|
statInfo = stInfo[stat.ST_MODE]
|
|
|
|
|
if stat.S_ISDIR(statInfo):
|
|
|
|
|
self.scanDirectory(absPath, listFiles,
|
|
|
|
|
skipPath, prefix, True)
|
|
|
|
|
|
|
|
|
|
def getListFilesTemplate(self, homeDir):
|
|
|
|
|
"""
|
|
|
|
|
Generation file list in user home directory, exclude mount dirs
|
|
|
|
|
"""
|
|
|
|
|
home = os.path.join(homeDir, "")
|
|
|
|
|
execStr = "mount"
|
|
|
|
|
textLines = self.execProg(execStr)
|
|
|
|
|
# skip directories in scanning
|
|
|
|
|
skipPaths = []
|
|
|
|
|
if textLines:
|
|
|
|
|
for line in textLines:
|
|
|
|
|
if home in line:
|
|
|
|
|
skipPath =\
|
|
|
|
|
line.partition(home)[2].rpartition(" type")[0]
|
|
|
|
|
skipPaths.append(skipPath)
|
|
|
|
|
# file list in user profile
|
|
|
|
|
listFiles = []
|
|
|
|
|
if not skipPaths:
|
|
|
|
|
self.printERROR(_("Mounting point for server resources not found"))
|
|
|
|
|
return False
|
|
|
|
|
self.scanDirectory(homeDir, listFiles, skipPaths)
|
|
|
|
|
return listFiles
|
|
|
|
|
|
|
|
|
|
def removeFilesInProfile(self, homeDir, pathListFile):
|
|
|
|
|
"""
|
|
|
|
|
Remove files which is absend in user profile
|
|
|
|
|
"""
|
|
|
|
|
# read file list from config
|
|
|
|
|
try:
|
|
|
|
|
filesTemplateTxt = open(pathListFile).read()
|
|
|
|
|
except:
|
|
|
|
|
return False
|
|
|
|
|
listFilesTemplate = filter(lambda x: x.strip(),
|
|
|
|
|
filesTemplateTxt.split("\n"))
|
|
|
|
|
filesTemplate = set(listFilesTemplate)
|
|
|
|
|
# Получаем файлы в домашней директории
|
|
|
|
|
listFilesHome = self.getListFilesTemplate(homeDir)
|
|
|
|
|
if listFilesHome is False:
|
|
|
|
|
return False
|
|
|
|
|
filesHome = set(listFilesHome)
|
|
|
|
|
filesRemove = list(filesHome - filesTemplate)
|
|
|
|
|
filesRemove.sort(lambda x, y: cmp(len(y), len(x)))
|
|
|
|
|
rmPath = ""
|
|
|
|
|
try:
|
|
|
|
|
for rmFile in filesRemove:
|
|
|
|
|
rmPath = os.path.join(homeDir, rmFile)
|
|
|
|
|
if os.path.islink(rmPath):
|
|
|
|
|
os.unlink(rmPath)
|
|
|
|
|
elif os.path.isfile(rmPath):
|
|
|
|
|
os.remove(rmPath)
|
|
|
|
|
elif os.path.isdir(rmPath):
|
|
|
|
|
os.rmdir(rmPath)
|
|
|
|
|
else:
|
|
|
|
|
os.remove(rmPath)
|
|
|
|
|
except:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def getRunCommandsWithEnv(self):
|
|
|
|
|
"""List run program"""
|
|
|
|
|
def getCmd(procNum):
|
|
|
|
|
cmdLineFile = '/proc/%s/cmdline'%procNum
|
|
|
|
|
environFile = '/proc/%s/environ'%procNum
|
|
|
|
|
try:
|
|
|
|
|
if os.path.exists(cmdLineFile) and \
|
|
|
|
|
os.path.exists(environFile):
|
|
|
|
|
return (open(cmdLineFile,'r').read().strip(),
|
|
|
|
|
open(environFile,'r').read().strip())
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
return ("","")
|
|
|
|
|
if not os.access('/proc',os.R_OK):
|
|
|
|
|
return []
|
|
|
|
|
return map(getCmd,
|
|
|
|
|
filter(lambda x:x.isdigit(),
|
|
|
|
|
os.listdir('/proc')))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def clearUserKey(self, userName):
|
|
|
|
|
"""Очищает пользовательский ключ ядра"""
|
|
|
|
|
# Ищем ключ в ядре и проверяем не выполняет ли он повторный вход
|
|
|
|
|
return True
|
|
|
|
|
if getKey(userName) and not \
|
|
|
|
|
filter(lambda x:"xdm/xdm\x00--login" in x[0] and \
|
|
|
|
|
("USER=%s"%userName) in x[1],self.getRunCommandsWithEnv()):
|
|
|
|
|
# очищаем
|
|
|
|
|
ret = clearKey(userName)
|
|
|
|
|
if ret == 0:
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
self.printERROR(_("Failed to clear the kernel key for user %s")\
|
|
|
|
|
%userName)
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
@safetyWrapper(native_errors=(TemplatesError,ClientError),
|
|
|
|
|
man_int=__("Manually interrupted"),
|
|
|
|
|
post_action=errorUmountUserRes)
|
|
|
|
|
def umountUserResAndSync(self, dv):
|
|
|
|
|
"""
|
|
|
|
|
Umount user resouces and synchronizatoin user profile
|
|
|
|
|
"""
|
|
|
|
|
self.initVars(dv)
|
|
|
|
|
try:
|
|
|
|
|
self.uid = int(self.clVars.Get('ur_uid'))
|
|
|
|
|
self.gid = int(self.clVars.Get('ur_gid'))
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
raise ClientError(_("Failed to determnate UID and GID"))
|
|
|
|
|
self.sync = self.clVars.Get('cl_client_sync') == 'on'
|
|
|
|
|
self.userName = self.clVars.Get("ur_login")
|
|
|
|
|
self.homeDir = self.clVars.Get('ur_home_path')
|
|
|
|
|
self.domain = self.clVars.Get("cl_remote_host")
|
|
|
|
|
try:
|
|
|
|
|
passwdUsers = map(lambda x: x[0],
|
|
|
|
|
map(lambda x: x.split(':'),
|
|
|
|
|
map(lambda x: x.strip(),
|
|
|
|
|
open("/etc/passwd").readlines())))
|
|
|
|
|
except:
|
|
|
|
|
self.printERROR(_("Failed to open /etc/passwd"))
|
|
|
|
|
return False
|
|
|
|
|
if not os.path.exists(self.homeDir):
|
|
|
|
|
self.printERROR(_("User home directory %s not found")%self.homeDir)
|
|
|
|
|
return False
|
|
|
|
|
currentDateStr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
|
|
|
|
# domain workstation work in local mode
|
|
|
|
|
if self.userName in passwdUsers:
|
|
|
|
|
configFileName = os.path.join(self.homeDir, self.configFileDesktop)
|
|
|
|
|
self.setVarToConfig("main", {"date_logout":currentDateStr},
|
|
|
|
|
configFileName)
|
|
|
|
|
self.printWARNING(_("User information from /etc/passwd is used"))
|
|
|
|
|
self.printSUCCESS(_("The local profile will be used"))
|
|
|
|
|
return True
|
|
|
|
|
hostAuth = self.clVars.Get("os_remote_auth")
|
|
|
|
|
# local mode
|
|
|
|
|
if not hostAuth or not self.domain:
|
|
|
|
|
self.printSUCCESS(_("The local profile will be used"))
|
|
|
|
|
return True
|
|
|
|
|
# check for domain workstation and [remote] was mounted
|
|
|
|
|
if not self.isDomain():
|
|
|
|
|
raise ClientError(_("The computer is not in the domain"))
|
|
|
|
|
# check is user in X session, do not umount user resources
|
|
|
|
|
if self.isSessionUser(self.userName):
|
|
|
|
|
self.printERROR(_("User %s is already in X session")%self.userName)
|
|
|
|
|
self.printERROR(
|
|
|
|
|
_("Failed to unmount user %s resource")%self.userName)
|
|
|
|
|
return False
|
|
|
|
|
# user package config
|
|
|
|
|
configFileName = os.path.join(self.homeDir, self.configFileDesktop)
|
|
|
|
|
self.setVarToConfig("main", {"date_logout":currentDateStr},
|
|
|
|
|
configFileName)
|
|
|
|
|
if os.path.exists(self.homeDir):
|
|
|
|
|
self.moveHomeDir(self.homeDir)
|
|
|
|
|
if self.sync:
|
|
|
|
|
self.tarSymLinks(self.homeDir,self.uid,self.gid)
|
|
|
|
|
else:
|
|
|
|
|
raise ClientError(_("Directory %s not found") % self.homeDir)
|
|
|
|
|
# get status sync
|
|
|
|
|
exitStr = iniParser(configFileName).getVar('main','status_sync')
|
|
|
|
|
# check on error or net full executed -> process
|
|
|
|
|
if exitStr == "process" or exitStr == "error":
|
|
|
|
|
self.sync = False
|
|
|
|
|
if self.clVars.Get("cl_profile_all_set") == "on":
|
|
|
|
|
osLinuxShort = "all"
|
|
|
|
|
else:
|
|
|
|
|
osLinuxShort = self.clVars.Get("os_linux_shortname")
|
|
|
|
|
# get mount resources
|
|
|
|
|
dictRes = self.getUserMountResources(self.userName, self.homeDir,False)
|
|
|
|
|
pathUnix = dictRes["profile"]["path"]
|
|
|
|
|
homeProfile = os.path.join(pathUnix, osLinuxShort)
|
|
|
|
|
if not isMount(pathUnix):
|
|
|
|
|
self.printERROR(_("Mounted remote resources for user %s not found")%
|
|
|
|
|
self.userName)
|
|
|
|
|
return False
|
|
|
|
|
try:
|
|
|
|
|
if self.sync:
|
|
|
|
|
# sync profiles local to domain
|
|
|
|
|
if not self.syncUser(self.userName, self.homeDir, "logout",
|
|
|
|
|
homeProfile,host=self.domain):
|
|
|
|
|
return False
|
|
|
|
|
finally:
|
|
|
|
|
# remove files, which hinder correct dm work
|
|
|
|
|
self.removeNoiseFiles(self.homeDir)
|
|
|
|
|
# remove private files
|
|
|
|
|
self.removePrivateFiles(self.homeDir)
|
|
|
|
|
# clean user password from root keys
|
|
|
|
|
self.clearUserKey(self.userName)
|
|
|
|
|
# umount user res
|
|
|
|
|
if not self.umountUserRes(self.homeDir):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
# remove empty directories
|
|
|
|
|
for name in dictRes.keys():
|
|
|
|
|
rpath = dictRes[name]["path"]
|
|
|
|
|
if os.path.exists(rpath) and not os.listdir(rpath):
|
|
|
|
|
try:
|
|
|
|
|
os.rmdir(rpath)
|
|
|
|
|
except:
|
|
|
|
|
self.printERROR(_("Failed to remove dir %s")% path)
|
|
|
|
|
return False
|
|
|
|
|
# remove Disks directory if it empty
|
|
|
|
|
pathDisks = os.path.join(self.homeDir,"Disks")
|
|
|
|
|
if os.path.exists(pathDisks) and not os.listdir(pathDisks):
|
|
|
|
|
try:
|
|
|
|
|
os.rmdir(pathDisks)
|
|
|
|
|
except:
|
|
|
|
|
self.printERROR(_("Failed to remove dir %s")% pathDisks)
|
|
|
|
|
return False
|
|
|
|
|
if self.sync:
|
|
|
|
|
self.printSUCCESS(_("User profile saved in the domain"))
|
|
|
|
|
self.setVarToConfig("main", {"status_sync":"success_logout"},
|
|
|
|
|
configFileName)
|
|
|
|
|
self.printSUCCESS(_("Domain user resource unmounted"))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def getMountUserPaths(self, homeDir=False):
|
|
|
|
|
"""Находит пользовательские примонтированные пути"""
|
|
|
|
|
# Имя пользователя
|
|
|
|
|
if not homeDir:
|
|
|
|
|
userName = self.clVars.Get("ur_login")
|
|
|
|
|
try:
|
|
|
|
|
homeDir = pwd.getpwnam(userName).pw_dir
|
|
|
|
|
except:
|
|
|
|
|
homeDir = os.path.join("/home",userName)
|
|
|
|
|
dirStart, dirEnd = os.path.split(homeDir)
|
|
|
|
|
mountTemplateDir = os.path.join(dirStart, ".%s" %dirEnd)
|
|
|
|
|
mountRemoteTemplateDir = os.path.join(dirStart, ".%s.remote" %dirEnd)
|
|
|
|
|
return filter(lambda x: x.startswith(homeDir) or\
|
|
|
|
|
x.startswith(mountTemplateDir) or\
|
|
|
|
|
x.startswith(mountRemoteTemplateDir),
|
|
|
|
|
map(lambda x: x.split(" ")[1],\
|
|
|
|
|
open("/proc/mounts").readlines()))
|
|
|
|
|
|
|
|
|
|
def execProg(self, cmdStrProg, inStr=False, envProg={}):
|
|
|
|
|
"""
|
|
|
|
|
Execute external program
|
|
|
|
|
"""
|
|
|
|
|
env_path = {"PATH":getpathenv()}
|
|
|
|
|
env = {}
|
|
|
|
|
env.update(os.environ.items() + env_path.items() + envProg.items())
|
|
|
|
|
retCode,programOut = runOsCommand(cmdStrProg,in_str=inStr,env_dict=env)
|
|
|
|
|
if not retCode:
|
|
|
|
|
return programOut
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def umountSleepPath(self, rpath):
|
|
|
|
|
"""
|
|
|
|
|
Unmount path, sleep by failed and repeat
|
|
|
|
|
"""
|
|
|
|
|
# check for mount
|
|
|
|
|
if isMount(rpath):
|
|
|
|
|
for waittime in [0,0.5,1,2]:
|
|
|
|
|
time.sleep(waittime)
|
|
|
|
|
if not self.execProg("umount %s"%rpath) is False \
|
|
|
|
|
or not isMount(rpath):
|
|
|
|
|
if not isMount(rpath):
|
|
|
|
|
return True
|
|
|
|
|
self.execProg("fuser -km %s"%rpath)
|
|
|
|
|
for waittime in [0.5, 0.5, 0.5, 0.5, 0.5, 0.5]:
|
|
|
|
|
time.sleep(waittime)
|
|
|
|
|
if not self.execProg("umount %s"%rpath) is False \
|
|
|
|
|
or not isMount(rpath):
|
|
|
|
|
if not isMount(rpath):
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
if isMount(rpath):
|
|
|
|
|
raise ClientError(_("Failed to unmount path %s")%rpath)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def umountUserRes(self, homeDir=False, removeEmpty=False):
|
|
|
|
|
"""
|
|
|
|
|
Unmount user directories
|
|
|
|
|
"""
|
|
|
|
|
for umountPath in self.getMountUserPaths(homeDir):
|
|
|
|
|
if not self.umountSleepPath(umountPath):
|
|
|
|
|
return False
|
|
|
|
|
if os.path.exists(umountPath) and not os.listdir(umountPath):
|
|
|
|
|
os.rmdir(umountPath)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def installProg(self,onlyEnv=False):
|
|
|
|
|
"""Наложение шаблонов на систему при инсталяции
|
|
|
|
|
|
|
|
|
|
onlyEnv - выполнить только добавление в calculate2.env
|
|
|
|
|
и client в автозапуск
|
|
|
|
|
"""
|
|
|
|
|
# Действие выход из домена
|
|
|
|
|
self.clVars.Set("cl_action", "install", True)
|
|
|
|
|
domain = self.clVars.Get("cl_remote_host")
|
|
|
|
|
domainLive = self.clVars.Get("cl_remote_host_live")
|
|
|
|
|
self.clVars.AppendToList("cl_merges", __app__, force=True)
|
|
|
|
|
# Добавление программы в инсталяционную переменную
|
|
|
|
|
if not appendProgramToEnvFile(__app__, self.clVars):
|
|
|
|
|
self.printERROR(_("Failed to save '%s'") %__app__ + " " +\
|
|
|
|
|
_("to %s") %self.clVars.Get("cl_env_path")[0])
|
|
|
|
|
return False
|
|
|
|
|
if domain or domainLive:
|
|
|
|
|
if not self.addDaemonAutostart("client"):
|
|
|
|
|
return False
|
|
|
|
|
if onlyEnv:
|
|
|
|
|
# apply templates (this appling client templates need
|
|
|
|
|
# for safety executing cl-install --startup for
|
|
|
|
|
# already domained computers
|
|
|
|
|
if self.clVars.Get("os_remote_auth") and \
|
|
|
|
|
not self.applyTemplatesFromSystem():
|
|
|
|
|
self.printERROR(_("Failed to apply install templates"))
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
if domain and not self.mountRemote():
|
|
|
|
|
return False
|
|
|
|
|
if not self.applyTemplatesFromSystem():
|
|
|
|
|
self.printERROR(_("Failed to apply install templates"))
|
|
|
|
|
return False
|
|
|
|
|
if domain:
|
|
|
|
|
self.printOK(_("The domain profile will be used") + " ...")
|
|
|
|
|
else:
|
|
|
|
|
self.printOK(_("The local profile will be used") + " ...")
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def getDefaultRunlevelDaemons(self):
|
|
|
|
|
"""Получаем всех демонов в default уровне"""
|
|
|
|
|
execStr = "rc-update show"
|
|
|
|
|
textLine = self.execProg(execStr)
|
|
|
|
|
if textLine is False:
|
|
|
|
|
self.printERROR(_("ERROR") + ": " + execStr)
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
splLines = filter(lambda x: len(x)==2 and "default" in x[1],\
|
|
|
|
|
map(lambda x: x.split("|"),textLine))
|
|
|
|
|
splLines = map(lambda x: x[0].strip(), splLines)
|
|
|
|
|
return splLines
|
|
|
|
|
|
|
|
|
|
def uninstallProg(self):
|
|
|
|
|
"""Наложение шаблонов на систему при деинсталяции"""
|
|
|
|
|
# Проверяем на root
|
|
|
|
|
if not self.isRoot():
|
|
|
|
|
return False
|
|
|
|
|
# Действие удаление
|
|
|
|
|
self.clVars.Set("cl_action", "uninstall", True)
|
|
|
|
|
# Удаляем переменные из env файлов
|
|
|
|
|
self.removeVars()
|
|
|
|
|
# Удаление программы из инсталяционной переменной
|
|
|
|
|
if not removeProgramToEnvFile(__app__, self.clVars):
|
|
|
|
|
self.printERROR(_("Failed to remove '%(app)s' from %(path)s")%
|
|
|
|
|
{'app':__app__,
|
|
|
|
|
'path':self.clVars.Get("cl_env_path")[0]})
|
|
|
|
|
return False
|
|
|
|
|
if not self.applyTemplatesFromSystem():
|
|
|
|
|
self.printERROR(_("Failed to apply uninstall templates"))
|
|
|
|
|
return False
|
|
|
|
|
if not self.delDaemonAutostart("client"):
|
|
|
|
|
return False
|
|
|
|
|
self.printOK(_("Apply uninstall templates"))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def delDaemonAutostart(self, daemon):
|
|
|
|
|
"""Удаляет демона из автозагрузки"""
|
|
|
|
|
defaultDaemons = self.getDefaultRunlevelDaemons()
|
|
|
|
|
if defaultDaemons is False:
|
|
|
|
|
return False
|
|
|
|
|
if daemon in defaultDaemons:
|
|
|
|
|
execStr = "rc-update del %s default" %daemon
|
|
|
|
|
textLine = self.execProg(execStr)
|
|
|
|
|
if textLine is False:
|
|
|
|
|
self.printERROR(_("ERROR") + ": " + execStr)
|
|
|
|
|
self.printERROR(_("Failed to delete from the default runlevel"))
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
return True
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def delDomain(self):
|
|
|
|
|
"""
|
|
|
|
|
Remove from domain
|
|
|
|
|
"""
|
|
|
|
|
pathRemote = "/var/calculate/remote"
|
|
|
|
|
foundMountRemote = isMount(pathRemote)
|
|
|
|
|
domain = self.clVars.Get("cl_remote_host")
|
|
|
|
|
if foundMountRemote:
|
|
|
|
|
textLineUmount = self.umountSleepPath(pathRemote)
|
|
|
|
|
if not textLineUmount:
|
|
|
|
|
return False
|
|
|
|
|
if not domain:
|
|
|
|
|
self.printWARNING(_("The computer is not in the domain"))
|
|
|
|
|
return True
|
|
|
|
|
# remove domain vars from env files
|
|
|
|
|
self.removeVars()
|
|
|
|
|
# apply templates for undomain
|
|
|
|
|
self.clVars.Set("cl_action", "undomain", True)
|
|
|
|
|
if not self.applyTemplatesFromSystem():
|
|
|
|
|
self.printERROR(_("Failed to apply undomain templates"))
|
|
|
|
|
return False
|
|
|
|
|
# Delete LDAP users from system and clear cache
|
|
|
|
|
if not self.cDelLdapSysUsersAndClearCache():
|
|
|
|
|
self.printERROR(_("Failed to clear user cache"))
|
|
|
|
|
return False
|
|
|
|
|
# restart dbus
|
|
|
|
|
self.restartDBus()
|
|
|
|
|
if not self.delDaemonAutostart("client"):
|
|
|
|
|
self.printERROR(
|
|
|
|
|
_("Failed to remove client service from autostart"))
|
|
|
|
|
return False
|
|
|
|
|
self.printSUCCESS(_("Computer removed from domain %s")%domain + " ...")
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def getUserPassword(self, pwDialog=False):
|
|
|
|
|
"""Получить пароль у пользователя
|
|
|
|
|
|
|
|
|
|
pwDialog - приглашение ввода пароля
|
|
|
|
|
"""
|
|
|
|
|
if os.readlink('/proc/self/fd/0') == '/dev/console':
|
|
|
|
|
os.system('chvt 1 &>/dev/null')
|
|
|
|
|
if not pwDialog:
|
|
|
|
|
pwDialog = _("Password")
|
|
|
|
|
userPwd = getpass.getpass(pwDialog+":")
|
|
|
|
|
return userPwd
|
|
|
|
|
|
|
|
|
|
def addDaemonAutostart(self, daemon):
|
|
|
|
|
"""Прописывает демона в автозагрузку"""
|
|
|
|
|
defaultDaemons = self.getDefaultRunlevelDaemons()
|
|
|
|
|
if defaultDaemons is False:
|
|
|
|
|
return False
|
|
|
|
|
if daemon in defaultDaemons:
|
|
|
|
|
return True
|
|
|
|
|
execStr = "rc-update add %s default" %daemon
|
|
|
|
|
textLine = self.execProg(execStr)
|
|
|
|
|
if textLine is False:
|
|
|
|
|
self.printERROR(_("ERROR") + ": " + execStr)
|
|
|
|
|
self.printERROR(_("Failed to add to the default runlevel"))
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def restartDBus(self):
|
|
|
|
|
"""Restart D-Bus service"""
|
|
|
|
|
return True
|
|
|
|
|
dbusDaemon = 'rc-service -i dbus'
|
|
|
|
|
existsDaemon = 'rc-service -e dbus'
|
|
|
|
|
# если установлена и запущена
|
|
|
|
|
if os.system(existsDaemon) == 0 and \
|
|
|
|
|
os.system(dbusDaemon + ' status &>/dev/null') == 0:
|
|
|
|
|
# пезапустить
|
|
|
|
|
if os.system(dbusDaemon + ' restart -- -s &>/dev/null') != 0:
|
|
|
|
|
self.printWARNING(_("Error restarting")+" "+dbusDaemon+" ...")
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def getInfoService(self, service, option, envFile=False):
|
|
|
|
|
"""Получить параметр сервиса из env"""
|
|
|
|
|
if not envFile:
|
|
|
|
|
if self.convObj == None:
|
|
|
|
|
# файл /var/calculate/remote/server.env
|
|
|
|
|
envFile = self.clVars.Get("cl_env_server_path")
|
|
|
|
|
if os.access(envFile, os.R_OK):
|
|
|
|
|
self.convObj = False
|
|
|
|
|
elif os.access("/var/calculate/remote/calculate.env", os.R_OK):
|
|
|
|
|
self.convObj = convertEnv()
|
|
|
|
|
if self.convObj:
|
|
|
|
|
return self.convObj.getVar(service, option)
|
|
|
|
|
if not self.optionsInfo:
|
|
|
|
|
if not envFile:
|
|
|
|
|
# файл /var/calculate/remote/server.env
|
|
|
|
|
envFile = self.clVars.Get("cl_env_server_path")
|
|
|
|
|
optInfo = self.clVars.GetRemoteInfo(envFile)
|
|
|
|
|
if optInfo is False:
|
|
|
|
|
return False
|
|
|
|
|
if optInfo:
|
|
|
|
|
self.optionsInfo = optInfo
|
|
|
|
|
value = ''
|
|
|
|
|
if service in self.optionsInfo and option in self.optionsInfo[service]:
|
|
|
|
|
value = self.optionsInfo[service][option]
|
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
@safetyWrapper(native_errors=(TemplatesError,ClientError),
|
|
|
|
|
man_int=__("Manually interrupted"))
|
|
|
|
|
def domain(self,dv):
|
|
|
|
|
self.initVars(dv)
|
|
|
|
|
if self.clVars.Get('cl_client_mount_set') == 'on':
|
|
|
|
|
return self.mountRemote()
|
|
|
|
|
else:
|
|
|
|
|
if self.clVars.Get('cl_localhost_set') == "on":
|
|
|
|
|
return self.delDomain()
|
|
|
|
|
else:
|
|
|
|
|
return self.addDomain()
|
|
|
|
|
|
|
|
|
|
def addDomain(self):
|
|
|
|
|
"""
|
|
|
|
|
Add to domain
|
|
|
|
|
"""
|
|
|
|
|
domainName = self.clVars.Get('cl_remote_host_new')
|
|
|
|
|
remoteHost = self.clVars.Get("cl_remote_host")
|
|
|
|
|
netDomain = self.clVars.Get("os_net_domain")
|
|
|
|
|
# get domain name
|
|
|
|
|
if "." in domainName:
|
|
|
|
|
domain = domainName
|
|
|
|
|
else:
|
|
|
|
|
domain = "%s.%s" %(domainName,netDomain)
|
|
|
|
|
# check domain by ping
|
|
|
|
|
for i in range(0,1):
|
|
|
|
|
try:
|
|
|
|
|
Pinger().ping(domain,1000,16)
|
|
|
|
|
break
|
|
|
|
|
except IPError as e:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
self.printERROR(_("Server %s does not respond")%domain)
|
|
|
|
|
return False
|
|
|
|
|
reFoundHostSamba = re.compile("Server=\[Samba.+\]")
|
|
|
|
|
resSmbClient = self.execProg("smbclient -N -L %s" %domain)
|
|
|
|
|
if not resSmbClient is False:
|
|
|
|
|
for string in resSmbClient:
|
|
|
|
|
if reFoundHostSamba.search(string):
|
|
|
|
|
foundHostSamba = True
|
|
|
|
|
break
|
|
|
|
|
if not foundHostSamba:
|
|
|
|
|
self.printERROR(_("Samba server not found in %s")%domain)
|
|
|
|
|
return False
|
|
|
|
|
if remoteHost and self.clVars.Get('cl_localhost_set') != 'on':
|
|
|
|
|
self.printERROR(_("The computer is already in the domain %s")\
|
|
|
|
|
%remoteHost)
|
|
|
|
|
self.printWARNING(_("Before joining the domain, "
|
|
|
|
|
"you need to remove it from the previous domain"))
|
|
|
|
|
self.printWARNING(_("Run 'cl-client -r'"))
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
foundMountRemote = isMount("/var/calculate/remote")
|
|
|
|
|
if foundMountRemote:
|
|
|
|
|
self.printERROR(_("Samba resource [%s] mounted")%\
|
|
|
|
|
"remote" + " ...")
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
def passwdQueue():
|
|
|
|
|
remotePw = self.clVars.Get('cl_remote_pw')
|
|
|
|
|
if remotePw:
|
|
|
|
|
yield remotePw
|
|
|
|
|
if remotePw:
|
|
|
|
|
self.printERROR(_("Wrong password"))
|
|
|
|
|
yield self.askPassword(\
|
|
|
|
|
_("Domain password for the desktop"),False)
|
|
|
|
|
|
|
|
|
|
pathRemote = "/var/calculate/remote"
|
|
|
|
|
for pwdRemote in passwdQueue():
|
|
|
|
|
if not os.path.exists(pathRemote):
|
|
|
|
|
os.makedirs(pathRemote)
|
|
|
|
|
if not self.mountSambaRes(domain,"client",pwdRemote,
|
|
|
|
|
0,0,"remote",pathRemote) is False:
|
|
|
|
|
self.printSUCCESS(
|
|
|
|
|
_("Samba resource [%s] mounted")%"remote")
|
|
|
|
|
self.clVars.Write("cl_remote_host", domain, True, "local")
|
|
|
|
|
self.clVars.Write("cl_remote_pw", pwdRemote, True, "local")
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
self.printERROR(
|
|
|
|
|
_("Failed to mount Samba resource [%s]")%"remote")
|
|
|
|
|
return False
|
|
|
|
|
servDn = self.getInfoService("ldap", "services_dn")
|
|
|
|
|
unixDn = self.getInfoService("unix", "dn")
|
|
|
|
|
bindDn = self.getInfoService("unix", "bind_dn")
|
|
|
|
|
bindPw = self.getInfoService("unix", "bind_pw")
|
|
|
|
|
# check info from server
|
|
|
|
|
if not (servDn and unixDn and bindDn and bindPw):
|
|
|
|
|
self.printERROR(_("Info not found on the server") + ": " +\
|
|
|
|
|
_("services DN or unix DN or bind DN or bind password"))
|
|
|
|
|
return False
|
|
|
|
|
self.clVars.Set("cl_action", "domain", True)
|
|
|
|
|
self.clVars.Set("os_remote_auth", domain)
|
|
|
|
|
if not self.applyTemplatesFromSystem():
|
|
|
|
|
self.printERROR(
|
|
|
|
|
_("Failed to apply install templates or domain templates"))
|
|
|
|
|
return False
|
|
|
|
|
# Рестартуем dbus
|
|
|
|
|
self.restartDBus()
|
|
|
|
|
if not self.addDaemonAutostart("client"):
|
|
|
|
|
return False
|
|
|
|
|
# Записываем переменную
|
|
|
|
|
self.clVars.Write("os_remote_auth", domain, True)
|
|
|
|
|
# Записываем текущую версию программы
|
|
|
|
|
currentVersion = self.clVars.Get("cl_ver")
|
|
|
|
|
self.clVars.Write("os_remote_client", currentVersion, True)
|
|
|
|
|
self.printSUCCESS(_("Computer added to domain %s")%domain)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def relevanceTemplates(self, hostAuth):
|
|
|
|
|
"""
|
|
|
|
|
Determine relevance appling templates by program version
|
|
|
|
|
"""
|
|
|
|
|
# '' or hostname
|
|
|
|
|
if hostAuth != self.clVars.Get("os_remote_auth"):
|
|
|
|
|
return False
|
|
|
|
|
if self.clTempl:
|
|
|
|
|
self.closeClTemplate()
|
|
|
|
|
self.clTempl = ProgressTemplate(self.setProgress,self.clVars,
|
|
|
|
|
cltObj=True)
|
|
|
|
|
# current program version
|
|
|
|
|
currentVersion = self.clVars.Get("cl_ver")
|
|
|
|
|
# version of program which appled templates
|
|
|
|
|
previousVersion = self.clVars.Get("os_remote_client")
|
|
|
|
|
cVersion,pVersion = self.clTempl._convertVers(currentVersion,previousVersion)
|
|
|
|
|
if cVersion != pVersion:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def closeClTemplate(self):
|
|
|
|
|
if self.clTempl:
|
|
|
|
|
if self.clTempl.cltObj:
|
|
|
|
|
self.clTempl.cltObj.closeFiles()
|
|
|
|
|
self.clTempl.closeFiles()
|
|
|
|
|
self.clTempl = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def applyRelevanceTemplates(self, hostAuth=""):
|
|
|
|
|
"""
|
|
|
|
|
Appling relevance templates
|
|
|
|
|
"""
|
|
|
|
|
if not self.relevanceTemplates(hostAuth):
|
|
|
|
|
if hostAuth:
|
|
|
|
|
# add to domain
|
|
|
|
|
self.clVars.Set("cl_action","domain",True)
|
|
|
|
|
else:
|
|
|
|
|
# del from domain
|
|
|
|
|
self.clVars.Set("cl_action","undomain",True)
|
|
|
|
|
self.clVars.Set("os_remote_auth", hostAuth)
|
|
|
|
|
# apply system templates
|
|
|
|
|
dirsAndFiles = self.applyTemplatesFromSystem()
|
|
|
|
|
if not dirsAndFiles:
|
|
|
|
|
if hostAuth:
|
|
|
|
|
self.printERROR(_("Failed to apply domain templates"))
|
|
|
|
|
else:
|
|
|
|
|
self.printERROR(_("Failed to apply undomain templates"))
|
|
|
|
|
return False
|
|
|
|
|
if hostAuth:
|
|
|
|
|
self.printSUCCESS(_("Templates set for network mode"))
|
|
|
|
|
currentVersion = self.clVars.Get("cl_ver")
|
|
|
|
|
self.clVars.Write("os_remote_client", currentVersion, True)
|
|
|
|
|
self.clVars.Write("os_remote_auth", hostAuth, True)
|
|
|
|
|
else:
|
|
|
|
|
self.printSUCCESS(_("Templates set for local mode"))
|
|
|
|
|
self.clVars.Delete("os_remote_auth")
|
|
|
|
|
self.clVars.Delete("os_remote_client")
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def cDelLdapSysUsersAndSyncCache(self):
|
|
|
|
|
"""Delete LDAP users from system and synchronize cache"""
|
|
|
|
|
cacheObj = userCache()
|
|
|
|
|
if not cacheObj.deleteCacheUsersFromSystem():
|
|
|
|
|
return False
|
|
|
|
|
if not cacheObj.syncCacheToLdap():
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def cAddCacheUsersFromSystem(self):
|
|
|
|
|
"""Add cache users from system"""
|
|
|
|
|
cacheObj = userCache()
|
|
|
|
|
if not cacheObj.addCacheUsersFromSystem():
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def cAddUserToCache(self, userName, userPwd):
|
|
|
|
|
"""Add user to cache"""
|
|
|
|
|
cacheObj = userCache()
|
|
|
|
|
pwdHash = self.getHashPasswd(userPwd, "shadow_ssha256")
|
|
|
|
|
if not cacheObj.addUserToCache(userName, pwdHash):
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def cDelLdapSysUsersAndClearCache(self):
|
|
|
|
|
"""Delete LDAP users from system and clear cache"""
|
|
|
|
|
cacheObj = userCache()
|
|
|
|
|
if not cacheObj.deleteCacheUsersFromSystem():
|
|
|
|
|
return False
|
|
|
|
|
if not cacheObj.clearCache():
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def moveHomeDirs(self):
|
|
|
|
|
"""Move home dirs /var/calculate/client-home -> /home
|
|
|
|
|
|
|
|
|
|
if user in cache
|
|
|
|
|
"""
|
|
|
|
|
cacheObj = userCache()
|
|
|
|
|
loginUsersData = cacheObj.getLoginDomainUsers()
|
|
|
|
|
if loginUsersData is False:
|
|
|
|
|
return False
|
|
|
|
|
previousHome = "/var/calculate/client-home"
|
|
|
|
|
if isMount(previousHome):
|
|
|
|
|
return True
|
|
|
|
|
if os.path.exists(previousHome):
|
|
|
|
|
flagMovedUsers = False
|
|
|
|
|
for userName,x,uid,gid,gecos,directory,shell in loginUsersData:
|
|
|
|
|
homeDir = directory
|
|
|
|
|
pathUserList = filter(lambda x: x, directory.split('/'))
|
|
|
|
|
if not pathUserList:
|
|
|
|
|
continue
|
|
|
|
|
pathUser = "/".join(pathUserList[1:])
|
|
|
|
|
srcDir = pathJoin(previousHome, pathUser)
|
|
|
|
|
if os.path.exists(srcDir) and not os.path.exists(homeDir):
|
|
|
|
|
flagMovedUsers = True
|
|
|
|
|
destDir = os.path.dirname(homeDir)
|
|
|
|
|
self.printWARNING(_("Moved %(src)s to %(dest)s")\
|
|
|
|
|
%{"src":srcDir,"dest":homeDir})
|
|
|
|
|
if not self.copyTemplateDir(srcDir, destDir):
|
|
|
|
|
return False
|
|
|
|
|
if flagMovedUsers and not os.listdir(previousHome):
|
|
|
|
|
os.rmdir(previousHome)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def mountRemote(self):
|
|
|
|
|
"""
|
|
|
|
|
Mount remote domain resource for domain workstation.
|
|
|
|
|
|
|
|
|
|
Alsa add to domain if found hostname and password
|
|
|
|
|
"""
|
|
|
|
|
domain = self.clVars.Get("cl_remote_host")
|
|
|
|
|
if domain:
|
|
|
|
|
foundMountRemote = isMount("/var/calculate/remote")
|
|
|
|
|
else:
|
|
|
|
|
self.printWARNING(_("This computer is not in the domain"))
|
|
|
|
|
if not self.applyRelevanceTemplates():
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
if foundMountRemote:
|
|
|
|
|
self.printWARNING(_("Samba resource [%s] mounted")%"remote" + \
|
|
|
|
|
" ...")
|
|
|
|
|
# apply domain templates
|
|
|
|
|
if domain:
|
|
|
|
|
self.clVars.flIniFile()
|
|
|
|
|
if not self.applyRelevanceTemplates(domain):
|
|
|
|
|
return False
|
|
|
|
|
# Delete LDAP users from system and synchronize cache
|
|
|
|
|
if not self.cDelLdapSysUsersAndSyncCache():
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
pathRemote = "/var/calculate/remote"
|
|
|
|
|
pwdRemote = self.clVars.Get("cl_remote_pw")
|
|
|
|
|
if not (domain and pwdRemote):
|
|
|
|
|
self.printERROR(_("Variable not found")+\
|
|
|
|
|
": cl_remote_pw ...")
|
|
|
|
|
return False
|
|
|
|
|
if not os.path.exists(pathRemote):
|
|
|
|
|
os.makedirs(pathRemote)
|
|
|
|
|
if self.mountSambaRes(domain,"client",pwdRemote,
|
|
|
|
|
0,0,"remote",pathRemote) is False:
|
|
|
|
|
self.printWARNING(_("Failed to mount Samba resource [%s]")%\
|
|
|
|
|
"remote" + " ...")
|
|
|
|
|
beforeRemoteAuth = self.clVars.Get('os_remote_auth')
|
|
|
|
|
# apply templates if current up-to-date
|
|
|
|
|
if not self.applyRelevanceTemplates():
|
|
|
|
|
return False
|
|
|
|
|
if not self.cAddCacheUsersFromSystem():
|
|
|
|
|
return False
|
|
|
|
|
if not self.moveHomeDirs():
|
|
|
|
|
return False
|
|
|
|
|
if beforeRemoteAuth != self.clVars.Get('os_remote_auth'):
|
|
|
|
|
self.restartDBus()
|
|
|
|
|
return True
|
|
|
|
|
self.printSUCCESS(_("Samba resource [%s] mounted") % "remote" +\
|
|
|
|
|
" ...")
|
|
|
|
|
# apply domain templates
|
|
|
|
|
if domain:
|
|
|
|
|
self.clVars.flIniFile()
|
|
|
|
|
beforeRemoteAuth = self.clVars.Get('os_remote_auth')
|
|
|
|
|
if not self.applyRelevanceTemplates(domain):
|
|
|
|
|
return False
|
|
|
|
|
# Delete LDAP users from system and synchronize cache
|
|
|
|
|
if not self.cDelLdapSysUsersAndSyncCache():
|
|
|
|
|
return False
|
|
|
|
|
if beforeRemoteAuth != self.clVars.Get('os_remote_auth'):
|
|
|
|
|
self.restartDBus()
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def updateEnvFiles(self):
|
|
|
|
|
"""Апдейт env файлов до версии 2.2"""
|
|
|
|
|
previousVersion = self.clVars.Get("os_remote_client")
|
|
|
|
|
flagUpdate = False
|
|
|
|
|
if not previousVersion:
|
|
|
|
|
# Апдейт
|
|
|
|
|
envFile="/var/calculate/calculate.env"
|
|
|
|
|
remoteHost = self.getInfoService("client", "cl_remote_host",
|
|
|
|
|
envFile=envFile)
|
|
|
|
|
remotePw = self.getInfoService("client", "cl_remote_pw",
|
|
|
|
|
envFile=envFile)
|
|
|
|
|
if remoteHost and remotePw:
|
|
|
|
|
self.clVars.Write("cl_remote_host", remoteHost, True, "local")
|
|
|
|
|
self.clVars.Write("cl_remote_pw", remotePw, True, "local")
|
|
|
|
|
envFile="/etc/calculate/calculate.env"
|
|
|
|
|
previousVersion = self.getInfoService("client", "os_remote_client",
|
|
|
|
|
envFile=envFile)
|
|
|
|
|
workHost = self.getInfoService("client", "os_remote_auth",
|
|
|
|
|
envFile=envFile)
|
|
|
|
|
if previousVersion and workHost:
|
|
|
|
|
self.clVars.Write("os_remote_client", previousVersion, True)
|
|
|
|
|
if workHost != "local":
|
|
|
|
|
self.clVars.Write("os_remote_auth", workHost, True)
|
|
|
|
|
self.printOK(_("Env files updated") + " ...")
|
|
|
|
|
flagUpdate = True
|
|
|
|
|
return flagUpdate
|
|
|
|
|
|
|
|
|
|
def setUserPasswordToServer(self):
|
|
|
|
|
"""Установка пароля пользователя на сервере"""
|
|
|
|
|
# Проверяем на root
|
|
|
|
|
if self.isRoot(False):
|
|
|
|
|
self.printERROR(_("The user is root"))
|
|
|
|
|
self.printWARNING(\
|
|
|
|
|
_("The program can be executed by a non-root user only"))
|
|
|
|
|
return False
|
|
|
|
|
# DNS имя хоста
|
|
|
|
|
server = self.ldapDataObj.getHost()
|
|
|
|
|
# DN пользователей
|
|
|
|
|
usersDN = self.ldapDataObj.getUsersDN()
|
|
|
|
|
if not (server and usersDN):
|
|
|
|
|
self.printERROR(_("The computer is not in the domain"))
|
|
|
|
|
self.printWARNING(_("Use passwd"))
|
|
|
|
|
return False
|
|
|
|
|
count = 2
|
|
|
|
|
# Получаем старый пароль пользователя
|
|
|
|
|
curPassword = self.getUserPassword(_("Enter the current password"))
|
|
|
|
|
if not curPassword:
|
|
|
|
|
self.printERROR(_("The current password is empty"))
|
|
|
|
|
for i in range(count):
|
|
|
|
|
count -= 1
|
|
|
|
|
# Получаем старый пароль пользователя
|
|
|
|
|
curPassword = self.getUserPassword(
|
|
|
|
|
_("Enter the current password"))
|
|
|
|
|
if curPassword:
|
|
|
|
|
break
|
|
|
|
|
self.printERROR(_("The current password is empty"))
|
|
|
|
|
if not curPassword:
|
|
|
|
|
return False
|
|
|
|
|
userDN = self.ldapDataObj.addDN("uid=%s"%os.environ["USER"], usersDN)
|
|
|
|
|
# Проверяем в LDAP сервере текущий пароль пользователя
|
|
|
|
|
ret, err = self.checkUserPwdLDAP(server, userDN, curPassword)
|
|
|
|
|
if not ret:
|
|
|
|
|
self.printERROR(err)
|
|
|
|
|
for i in range(count):
|
|
|
|
|
# Получаем старый пароль пользователя
|
|
|
|
|
curPassword = self.getUserPassword(
|
|
|
|
|
_("Enter the current password"))
|
|
|
|
|
if not curPassword:
|
|
|
|
|
self.printERROR(_("The current password is empty"))
|
|
|
|
|
continue
|
|
|
|
|
# Проверяем в LDAP сервере текущий пароль пользователя
|
|
|
|
|
ret, err = self.checkUserPwdLDAP(server, userDN, curPassword)
|
|
|
|
|
if ret:
|
|
|
|
|
break
|
|
|
|
|
self.printERROR(err)
|
|
|
|
|
if not ret:
|
|
|
|
|
return False
|
|
|
|
|
password = self.getUserPwd({"p":""}, "p", False)
|
|
|
|
|
if password is False:
|
|
|
|
|
for i in range(2):
|
|
|
|
|
password = self.getUserPwd({"p":""}, "p", False)
|
|
|
|
|
if password:
|
|
|
|
|
break
|
|
|
|
|
if password is False:
|
|
|
|
|
return False
|
|
|
|
|
# Переменные для записи в env файл
|
|
|
|
|
varsConfig = {"unix_hash":self.getHashPasswd(password,"ssha"),
|
|
|
|
|
"samba_lm_hash":self.getHashPasswd(password,"lm"),
|
|
|
|
|
"samba_nt_hash":self.getHashPasswd(password,"nt"),
|
|
|
|
|
"samba_nt_hash_old":self.getHashPasswd(curPassword,"nt")}
|
|
|
|
|
if filter(lambda x: not x, varsConfig.values()):
|
|
|
|
|
return False
|
|
|
|
|
# ~/.calculate/server.env
|
|
|
|
|
fileConfig = os.path.join(os.environ["HOME"], self.configFileServer)
|
|
|
|
|
if not self.setServerCommand(["passwd_samba"], varsConfig, fileConfig):
|
|
|
|
|
return False
|
|
|
|
|
self.printOK(_("%s's password changed")%os.environ["USER"] + \
|
|
|
|
|
" ...")
|
|
|
|
|
self.printWARNING(_("The password will be changed when you log "
|
|
|
|
|
"out from the X session"))
|
|
|
|
|
return True
|
|
|
|
|
|