Example #1
0
    def updateUsersProcesses(self, cbChanged):
        """
        Update list of users and processes.
        Instead of using who or similar, look for dbus-launch or
        another process. This is because we need the PID of one of the users
        processes to get misc. environment variables.
        Because of this it's convenient to update users and processes
        in the same place.
        cbChanged is called with the value True if the list of users has
        changed, otherwise False.
        """
        # actually a list of files in /proc, but the PIDs should be the only things changing
        pids = os.listdir('/proc')
        if pids == self._prevPIDList:
            cbChanged(False)
            return
        self._prevPIDList = pids
        
        cfg = config.get()
        
        import re
        # What we're matching:
        # Mon May 25 19:59:23 2009 jss      23043 /bin/bash
        re_ps = re.compile(r'^(\S+\s*\S+\s*\S+\s*\S+\s*\S+)\s*(\S+)\s*(\S+)\s*(.+)$')
        re_number = re.compile(r'^\d+$')
        cmd_login = cfg.get('Agent', 'login cmd')
        
        args = ['ww', '-e', '-o', 'lstart,user,pid,args']
        env = {'LC_ALL': 'C'}
        d = utils.getProcessOutput('/bin/ps', args, env)
        wait = defer.waitForDeferred(d)
        yield wait
        output = wait.getResult()
        
        processes = {} # {user: [ (pid, commandline)] }
        loginProcesses = [] # [ (logintime, user, pid, commandline) ]
        for line in output.splitlines()[1:]: # skip header
            m = re_ps.match(line)
            if not m:
                log.err('ps regex didn\'t match %s' % line)
                continue
            lstart, user, pid, commandline = m.groups()
            user = user.decode('utf-8')
            commandline = commandline.decode('utf-8', 'replace')
            
            # handle case where ps returns UID, e.g. for long usernames
            if re_number.match(user):
                uid = user
                try:
                    user = getpwuid(int(uid)).pw_name.decode('utf-8')
                except KeyError:
                    continue
                
            processes.setdefault(user, []).append((int(pid), commandline))

            if commandline.startswith(cmd_login):
                loginProcesses.append((lstart, user, int(pid), commandline))
        
        self.processes = processes
        
        loginPIDs = [l[2] for l in loginProcesses]
        if loginPIDs == self._loginPIDs:
            cbChanged(False)
            return
        self._loginPIDs = loginPIDs
        
        log.debug('login processes: %s' % loginProcesses)
        users = {}
        for lstart, user, pid, commandline in loginProcesses:
            try:
                logintime = time.mktime(time.strptime(lstart))
            except ValueError:
                log.err('failed to parse lstart \'%s\'' % lstart)
                continue
            try:
                env = dict(
                              ( var.split('=', 1) for var in
                                open('/proc/%s/environ' % pid, 'r').read().split('\x00') if var )
                            )
                display = env['DISPLAY']
                if 'SSH_CLIENT' in env: # remote login
                    clientIP = env['SSH_CLIENT'].split(None, 1)[0]
                    wait = defer.waitForDeferred(self._maybeResolve(clientIP))
                    yield wait
                    try:
                        client = wait.getResult()
                    except socket.error:
                        client = clientIP
                    
                    HWAddr = self._getHWAddr(clientIP)
                else:
                    client = ''
                    HWAddr = self._getOwnHWAddr()
                
                if 'LTSP_CLIENT' in env:
                    ctype = 'ltsp'
                else:
                    ctype = 'other'
                
                ukey = (user, client, display)
                try:
                    userobj = users[ukey] = self.users[ukey]
                except KeyError:
                    uenv = {}
                    for var in ('HOME', 'LANG', 'DISPLAY'):
                        uenv[var] = env[var]
                    name = getpw(user).pw_gecos.decode('utf-8', 'replace')
                    groups = getgroups(user)
                    
                    userobj = users[ukey] = User()
                    userobj.uid = getpw(user).pw_uid
                    userobj.gid = getpw(user).pw_gid
                    userobj.username = user
                    userobj.client = client
                    userobj.clientHWAddr = HWAddr
                    userobj.display = display
                    userobj.name = name
                    userobj.groups = groups
                    userobj.env = uenv
                    userobj.clientType = ctype
                    userobj.logintime = logintime
                
            except (IOError, OSError, KeyError, IndexError):
                log.err()
                log.err(env)
                continue
        
        self.users = users
        cbChanged(True)
Example #2
0
    def updateUsersProcesses(self, cbChanged):
        """
        Update list of users and processes.
        """
        import re
        # What we're matching:
        # Mon May 25 19:59:23 2009 jss      23043 /bin/bash
        re_ps = re.compile(r'^(\S+\s*\S+\s*\S+\s*\S+\s*\S+)\s*(\S+)\s*(\S+)\s*(.+)$')
        re_number = re.compile(r'^\d+$')
        cmd_login = '******'
        
        args = ['-ww', '-ax', '-o', 'lstart,user,pid,command']
        env = {'LC_ALL': 'C'}
        d = utils.getProcessOutput('/bin/ps', args, env)
        wait = defer.waitForDeferred(d)
        yield wait
        output = wait.getResult()
        
        processes = {} # {user: [ (pid, commandline)] }
        loginProcesses = [] # [ (logintime, user, pid, commandline) ]
        for line in output.splitlines()[1:]: # skip header
            m = re_ps.match(line)
            if not m:
                log.err('ps regex didn\'t match %s' % line)
                continue
            lstart, user, pid, commandline = m.groups()
            user = user.decode('utf-8')
            commandline = commandline.decode('utf-8', 'replace')
            
            # handle case where ps returns UID, e.g. for long usernames
            if re_number.match(user):
                uid = user
                try:
                    user = getpwuid(int(uid)).pw_name.decode('utf-8')
                except KeyError:
                    continue
                
            processes.setdefault(user, []).append((int(pid), commandline))

            if commandline.startswith(cmd_login):
                loginProcesses.append((lstart, user, int(pid), commandline))
        
        self.processes = processes
        
        loginPIDs = [l[2] for l in loginProcesses]
        if loginPIDs == self._loginPIDs:
            cbChanged(False)
            return
        self._loginPIDs = loginPIDs
        
        if not self._HWAddr:
            d = self._getOwnHWAddr()
            wait = defer.waitForDeferred(d)
            yield wait
            self._HWAddr = wait.getResult()
        
        log.debug('login processes: %s' % loginProcesses)
        users = {}
        for lstart, user, pid, commandline in loginProcesses:
            try:
                logintime = time.mktime(time.strptime(lstart))
            except ValueError:
                log.err('failed to parse lstart \'%s\'' % lstart)
                continue
        
            client = ''
            display = ''
            
            ukey = (user, client, display)
            try:
                userobj = users[ukey] = self.users[ukey]
            except KeyError:
                name = getpw(user).pw_gecos.decode('utf-8', 'replace')
                groups = getgroups(user)
                
                userobj = users[ukey] = User()
                userobj.uid = getpw(user).pw_uid
                userobj.gid = getpw(user).pw_gid
                userobj.username = user
                userobj.client = client
                userobj.clientHWAddr = self._HWAddr
                userobj.display = display
                userobj.name = name
                userobj.groups = groups
                userobj.env = {"PATH":"/bin:/sbin:/usr/bin:/usr/sbin"}
                userobj.logintime = logintime
        
        self.users = users
        log.debug(users)
        cbChanged(True)