Below is the file 'client/plugins/leftstaff.py' from this revision. You can also download the file.


import re
import os
import pwd
import sets
import stat
import glob
from phonehome import urgency
from config import install_path

left = ('mtearle', 'adrian', 'achadd', 'bernard', 'ceaves', 'cphillips', 'claire', 'dunc', 'luyer', 'rng', 'packrat', 'grahame', 'gbowland')

def run():
    rv = []
    for username in left:
        try:
            pwent = pwd.getpwnam(username)
        except:
            continue

        rv.append((urgency['notice'], 'user "%s" has account (uid %d)' % (username, pwent[2])))
        homedir = pwent[5]
        if os.access(os.path.join(homedir, '.ssh', 'authorized_keys'), os.R_OK):
            rv.append((urgency['notice'], 'user "%s" has SSH access' % (username)))
        for line in open('/etc/shadow'):
            fields = line.split(':')
            u, p = fields[0], fields[1]
            if u != username:
                continue
            if len(p) > 0 and p[0] != '!' and p[0] != '*':
                rv.append((urgency['notice'], 'user "%s" can log in with a password' % (username)))


    def read_apache_config(initial_set):
        # I wish we had case insensitive regexps in Python
        include_re = re.compile(r'^[ \t]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee] ([^ \t]+)$')
        authuser_re = re.compile(r'^[ \t]*[Aa][Uu][Tt][Hh][Uu][Ss][Ee][Rr][Ff][Ii][Ll][Ee] ([^ \t#]+)$')
        pw = sets.Set()
        known_files, visited = sets.Set(initial_set), sets.Set()
        while True:
            to_visit = known_files - visited
            if not to_visit:
                break
            for file in to_visit:
                def is_dir(f):
                    return stat.S_ISDIR(os.stat(f)[stat.ST_MODE])
                def add_dir(f):
                    files = os.listdir(f)
                    for f in files:
                        if is_dir(f):
                            add_dir(f)
                        else:
                            known_files.add(f)
                def resolve_include(i):
                    # see http://httpd.apache.org/docs/2.2/mod/core.html#include
                    # NB: python's fnmatch() doesn't like the "^" character; replace it with !
                    i = i.replace('[^', '[!')
                    g = glob.glob(i)
                    for f in glob.glob(i):
                        if not os.access(f, os.R_OK):
                            continue
                        if is_dir(f):
                            # recursively add every file in the directory
                            add_dir(f)
                        else:
                            known_files.add(f)
                def visit_file():
                    if os.access(file, os.R_OK):
                        for line in open(file):
                            m = include_re.match(line)
                            if m:
                                inc = m.groups()[0].strip()
                                resolve_include(inc)
                            m = authuser_re.match(line)
                            if m:
                                pw.add(m.groups()[0].strip())
                try:
                    visit_file()
                except:
                    pass
                visited.add(file)
        return pw

    def locate_htaccess_files():
        files = os.popen3('/usr/bin/locate .htaccess')[1].read()
        files = [t.strip() for t in files.split('\n')]
        return filter(None, files)

    config_files = ['/etc/apache/httpd.conf', '/etc/apache2/httpd.conf', '/etc/apache2/apache2.conf']
    config_files += locate_htaccess_files()
    http_passwd_files = read_apache_config(config_files)
    for http_passwd in http_passwd_files:
        if not os.access(http_passwd, os.R_OK):
            continue
        rv.append((urgency['info'], 'active http access file: %s' % (http_passwd)))
        for line in open(http_passwd):
            fields = line.split(':')
            if len(fields) != 2:
                continue
            username = fields[0]
            if username in left:
                rv.append((urgency['notice'], 'user "%s" has HTTP access via %s' % (username, http_passwd)))
    return rv