Esempio n. 1
0
 def initVars(self,datavars=None):
     """Primary variables initialization"""
     if not datavars:
         self.clVars = DataVarsDesktop()
         self.clVars.importDesktop()
         self.clVars.flIniFile()
     else:
         self.clVars = datavars
Esempio n. 2
0
class Desktop:
    """
    Desktop logic object

    Has fundamental method createHome for configure user profile
    """
    # username
    userName = ""
    verbose = False
    
    def __init__(self):
        self.homeDir = ""
        self.clTempl = None
        self.clVars = None

    def createCryptDir(self,userName,uid,gud,userDir):
        """
        Создать шифрование домашней директории, или подключить существующую
        """
        userPwd = getKey(userName)
        if not userPwd or userPwd == "XXXXXXXX":
            raise DesktopError(_("User password not found"))
        ecryptfsPath = path.join('/home/.ecryptfs',userName)
        if path.exists(ecryptfsPath):
            for d in (".ecryptfs",".Private"):
                source,target = path.join(ecryptfsPath,d),path.join(userDir,d)
                if not path.lexists(target):
                    os.symlink(source,target)
            try:
                if not mountEcryptfs(userName,userPwd,userDir):
                    raise DesktopError(_("Failed to mount ecrypted data"))
            except CommonError as e:
                raise DesktopError(_("Failed to mount ecrypted data")+": \"%s\""%str(e))
        else:
            tf = None
            try:
                # если профиль содержит только данные от бутстрапа core
                if isBootstrapDataOnly(userDir):
                    if childMounts(userDir):
                        raise DesktopError(
                            _("Failed to create encrypt user profile")+":"+
                            _("User home directory contains mount points"))
                    # поместить данные во временный tarfile
                    calculateName = ".calculate"
                    calculatePath = path.join(userDir,calculateName)
                    tf = tempfile.TemporaryFile()
                    with tarfile.open(fileobj=tf,mode='w:') as tarf:
                        tarf.add(calculatePath,calculateName)
                    tf.flush()
                    tf.seek(0)
                    # удалить эти данные
                    shutil.rmtree(calculatePath)

                # создать шифрованные данные
                e = process('/usr/bin/ecryptfs-setup-private','-u',userName,
                            '-b','-l',userPwd,stderr=STDOUT)
                if e.failed():
                    raise DesktopError(e.read())
                # если были данные от бутстрапа, то распаковать их
                if tf:
                    with tarfile.open(fileobj=tf,mode='r:') as tarf:
                        tarf.extractall(userDir)
            except Exception as e:
                if tf:
                    tf.seek(0)
                    bakArchName = path.join(userDir,".calculate.tar.bz2")
                    with open(bakArchName,'w') as f:
                        f.write(tf.read())
                raise DesktopError(str(e)+
                    _("Failed to create encrypt user profile"))
            finally:
                if tf:
                    tf.close()

    def createUserDir(self, userName, uid, gid, userDir, mode=0700):
        """
        Create user directory with need uid and gid
        """
        if not path.exists(userDir):
            os.makedirs(userDir)
            if mode:
                os.chmod(userDir,mode)
            os.chown(userDir,uid,gid)
            return True
        else:
            raise DesktopError(_("Path %s exists") %userDir)

    def displayTemplatesApplied(self,dirsFiles):
        """
        Display templates are applied (--verbose)
        """
        self.printSUCCESS(_("The following files were changed")+":")
        for nameF in dirsFiles[1]:
            nameFile = nameF
            if nameFile[:1] != "/":
                nameFile = "/" + nameFile
            self.printSUCCESS(" "*5 + nameFile)

    def applyTemplatesFromUser(self):
        """Apply templates for user"""
        if self.clTempl:
            self.closeClTemplate()

        templates_locate = self.clVars.Get('cl_templates_locate')
        self.clVars.Set("cl_template_path",
            map(lambda x:x[1],
            filter(lambda x:x[0] in templates_locate,
            zip(self.clVars.Get('cl_template_location'),
                self.clVars.Get('cl_template_path')))),
            True)

        self.clTempl = ProgressTemplate(self.setProgress,self.clVars,
                                        cltObj=False,
                                        printERROR=self.printERROR,
                                        printWARNING=self.printWARNING,
                                        askConfirm=self.askConfirm,
                                        printSUCCESS=self.printSUCCESS,
                                        userProfile=True)
        dirsFiles = self.clTempl.applyTemplates()
        if self.clTempl.getError():
            self.printERROR(self.clTempl.getError().strip())
            return False
        else:
            return dirsFiles

    def initVars(self,datavars=None):
        """Primary variables initialization"""
        if not datavars:
            self.clVars = DataVarsDesktop()
            self.clVars.importDesktop()
            self.clVars.flIniFile()
        else:
            self.clVars = datavars

    def closeClTemplate(self):
        if self.clTempl:
            if self.clTempl.cltObj:
                self.clTempl.cltObj.closeFiles()
            self.clTempl.closeFiles()
            self.clTempl = None

    def umountUserRes(self, error):
        """
        Umount user directory
        """
        self.closeClTemplate()
        if error and self.homeDir:
            umountPaths = self.getMountUserPaths(self.homeDir)
            ret = True
            for umountPath in umountPaths:
                if not self.umountSleepPath(umountPath):
                    ret = False
                    break
            return ret

    @safetyWrapper(native_errors=(TemplatesError,DesktopError,CommonError),
                   man_int=__("Configuration manually interrupted"),
                   post_action=umountUserRes)
    def createHome(self, datavars=None):
        """
        Creating user profile and userdir
        """
        self.initVars(datavars)
        self.verbose = self.clVars.Get('cl_verbose_set') == 'on'
        #uid = os.getuid()
        #try:
        #    realUserName = pwd.getpwuid(uid).pw_name
        #except:
        #    realUserName = ""
        userName = self.clVars.Get("ur_login")
        uidGid = False
        if self.clVars.isModuleInstalled("client"):
            # domain host
            domain = self.clVars.Get("client.cl_remote_host")
            # authorized in domain or local
            hostAuth = self.clVars.Get("client.os_remote_auth")
        else:
            domain = ""
            hostAuth = ""
        uid = self.clVars.Get('ur_uid')
        gid = self.clVars.Get('ur_gid')
        if not uid or not gid:
            raise DesktopError(_("Failed to determine the user UID"))
        uid,gid = int(uid),int(gid)

        self.homeDir = self.clVars.Get('ur_home_path')
        rootPath = self.clVars.Get('cl_root_path')
        # real path to home dir
        self.homeDir = path.join(rootPath, self.homeDir[1:])
        if not path.exists(self.homeDir):
            self.startTask(_("Creating the home directory for %s")%self.homeDir)
            self.createUserDir(userName,uid,gid,self.homeDir)
            self.endTask()
        if (self.clVars.Get('ur_home_crypt_set') == 'on' and
            self.clVars.Get('install.cl_autologin') != userName):
            self.createCryptDir(userName,uid,gid,self.homeDir)

        domainUser = self.clVars.Get('ur_domain_set') == 'on'
        lastTimestamp = templateFunction.getLastElog()
        iniEnv = path.join(self.homeDir,'.calculate/ini.env')
        userIni = iniParser(iniEnv)
        userTimestamp = userIni.getVar('main','elog').encode('utf-8')

        if (domainUser or not path.exists(iniEnv) or 
            userTimestamp != lastTimestamp):
            # action - "user profile configuration"
            self.clVars.Set("cl_action", "desktop", True)
            # apply user profiles
            self.startTask(_("Setting up the user profile"),progress=True)
            dirsAndFiles = self.applyTemplatesFromUser()
            self.endTask()
            if not dirsAndFiles:
                raise DesktopError(_("Failed to apply user profile templates"))
            self.printSUCCESS(_("User account %s is configured")%userName + " ...")
        return True

    def getMountUserPaths(self, homeDir=False):
        """
        Found user resources
        """
        if not homeDir:
            userName = self.clVars.Get("ur_login")
            homeDir = self.clVars.Get("ur_home_path")
        if not homeDir:
            raise DesktopError(_("Failed to determine home directory"))
        dirStart, dirEnd = path.split(homeDir)
        mountProfileDir = path.join(dirStart, ".%s" %dirEnd)
        mountRemoteProfileDir = path.join(dirStart, ".%s.remote" %dirEnd)
        return filter(lambda x: x.startswith(homeDir) or\
                      x.startswith(mountProfileDir) or\
                      x.startswith(mountRemoteProfileDir),
                      map(lambda x: x.split(" ")[1],\
                          open("/proc/mounts").readlines()))

    def execProg(self, cmdStrProg, inStr=False, envProg={}):
        """
        Exec 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):
                    self.printERROR(_("Failed to unmount directory %s")%rpath)
                    return False
        return True

    @safetyWrapper(native_errors=(TemplatesError,DesktopError),
                   man_int=__("Logout aborted"),
                   post_action=umountUserRes,
                   success_message=__("The user logged out from the session!"),
                   failed_message=__("Unable to logout the user"))
    def userLogout(self, datavars=None):
        """
        Raise user logout throught dbus
        """
        self.initVars(datavars)
        if not self.clVars.Get('ur_login') in \
            self.clVars.Get('cl_desktop_online_user'):
            raise DesktopError(_("X session users not found"))
        urLogin = self.clVars.Get('ur_login')
        display = self.clVars.Select('cl_desktop_online_display',
                    where='cl_desktop_online_user',eq=urLogin,limit=1)
        session = self.clVars.Get('cl_desktop_xsession')
        if session == 'xfce':
            logoutCommand = "/usr/bin/qdbus org.xfce.SessionManager " \
                "/org/xfce/SessionManager Logout False False"
        elif session == 'kde':
            logoutCommand = "/usr/bin/kquitapp ksmserver"
        elif session == 'gnome':
            logoutCommand = "/usr/bin/qdbus org.gnome.SessionManager " \
                "/org/gnome/SessionManager Logout 1"
        else:
            raise DesktopError(_("Unable to detect the X session"))
        if process("su",urLogin,"-c",
            ("DISPLAY=:%s "%display)+logoutCommand).failed():
            raise DesktopError(_("Unable to send the logout command"))
        for i in range(0,20):
            if filter(lambda x: "xdm/xdm\x00--logout" in x,
                    getRunCommands()):
                break
            time.sleep(0.5)
        if filter(lambda x: "xdm/xdm\x00--logout" in x,
                 getRunCommands()):
            self.startTask(_("Waiting for completion of the user logout"))
            for i in range(0,300):
                if not filter(lambda x: "xdm/xdm\x00--logout" in x,
                    getRunCommands()):
                    return True
                time.sleep(1)
                self.endTask()
            else:
                raise DesktopError(_("Unable to wait for completion "
                                     "of the user logout"))
        if self.clVars.Get('ur_login') in \
            self.clVars.Get('cl_desktop_online_user'):
            raise DesktopError(_("Wrong logout"))
        return True