#! /usr/bin/python3

"Pops you into a user's directory as that user"

import sys
import os
import re
import pwd,grp
import glob
import time

def procmounts():
    fd=open('/proc/mounts','r')
    r={}
    for line in fd:
        bits=line.split(' ')
        if len(bits)<5: continue
        device=bits[0]
        mountpoint=bits[1]
        filesystem=bits[2]
        options=bits[3]
        r[mountpoint]=device
    fd.close()
    return r
    

def setfsoptions(fstypes, newoptions, excluded_mountpoints=[]):
    'Returns list of mountpoints changed'
    mounts=procmounts()
    fstab=open('/etc/fstab','r').readlines()
    o=[]
    remountcmds=[]
    for line in fstab:
        bits=line.split()
        foundoptions=[]
        if len(bits) > 3:
            # /dev/Volgroup00/lv_root /                       ext3    defaults,usrquota        1 1
            device=bits[0]
            mountpoint=bits[1]
            fstype=bits[2]
            fsoptions=bits[3]
            for someoption in fsoptions.split(','):
                if someoption in newoptions:
                    foundoptions.append(someoption)
            if (len(foundoptions)<len(newoptions)) and (fstype in fstypes) and (device not in excluded_mountpoints) and (mountpoint not in excluded_mountpoints):
                for newoption in newoptions:
                    if newoption not in foundoptions: bits[3]+=','+newoption
                fsoptions=bits[3]
                line='\t'.join(bits)+'\n'
                if mountpoint in mounts:
                    remountcmds.append("mount -t %s -o remount,%s %s %s" % (fstype, fsoptions, device,mountpoint))
        o.append(line)
    if len(remountcmds)==0:
        return

    # Rewrite fstab for changes:
    fd = open('/etc/fstab','w')
    fd.writelines(o)
    fd.close()
    cmd = ' && ' .join(remountcmds)
    sys.stderr.write('# '+cmd+'\n')
    sys.stderr.flush()
    rc = os.system(cmd)
    if rc!=0:
        sys.stderr.write('# Rolling back /etc/fstab\n')
        sys.stderr.flush()
        fd=open('/etc/fstab','w');
        fd.writelines(fstab)
        fd.close()

def create_ahs_user():
    # It seemed like a good idea to fix this performance/corruption hog at the same time ...
    setfsoptions(['ext3','ext4'], ['noatime','acl'],     excluded_mountpoints=['/boot',]);
    scriptie='''
#! /bin/sh

# Maybe we have ACL's in place already:
cd /
if getfacl etc/valiases | grep -q '^group:ahs:' ; then
    exit;
fi

# Create the user
if ! id ahs > /dev/null 2>&1 ; then
    useradd -u 442 -m ahs
    rm -f ~ahs/.bash_logout
fi

# Install FACL's:
if ! [ -x /usr/bin/setfacl ] ; then
    yum -y install acl 1>&2
fi


EXIMFILES='/etc/aliases /etc/backupmxhosts /etc/demodomains /etc/demouids /etc/demousers /etc/domainusers /etc/exim.mailertable /etc/eximrejects /etc/localaliases /etc/localdomains /etc/mailhelo /etc/mailips /etc/mailproviders/rim/ips /etc/relayhosts /etc/relayhosts.afrihost /etc/secondarymx /etc/senderverifybypasshosts /etc/skipsmtpcheckhosts /etc/spammeripblocks /etc/spammers /etc/trustedmailhosts /etc/userdomains '

EXIMDIRS='/etc/valiases /etc/vdomainaliases /etc/vfilters'

# LOG FILES
setfacl -m g:ahs:r \
    /var/log/exim* \
    /var/log/messages* \
    /var/log/maillog* \
    /var/log/pslog* \
    /etc/httpd/conf/*.conf \
    /etc/httpd/conf/includes/*.conf \
    /usr/local/apache/logs/*_log \
    /var/log/mysql* \
    /var/lib/mysql/`hostname -f `.err \
    $EXIMFILES 2>/dev/null

# LOG FILES
setfacl -Rdm g:ahs:rx,g::rx  \
    $EXIMDIRS 2>/dev/null

'''
    os.system(scriptie)

def droppriv(target=".", quiet=False, groups=[]):
    "Drop root privileges"
    import posix,pwd
    stat = os.stat(target)
    uid = stat.st_uid
    if os.getuid==uid:
        return # job's done already
    # gid = stat.st_gid
    try:
        gids = [grp.getgrnam(x).gr_gid for x in groups]
        posix.setgroups(gids)
    except:
        if not quiet: sys.stderr.write("Cannot join groups %s :(\n" % ','.join(groups));
    gid = pwd.getpwuid(uid).pw_gid
    try:
        posix.setgid(gid)
        posix.setuid(uid)
        posix.seteuid(uid)
    except:
        if not quiet:
            sys.stderr.write("We are already unprivileged :)\n")
    uid=os.getuid()
    if uid==0 or gid==0:
        raise Exception("Oops - we dropped privilege to root: that's probably wrong");
    
    os.environ['HOME'] = pwd.getpwuid(uid).pw_dir
    os.environ['PS1'] = r'\t \u@\h [\w]\$ '
    return os.environ['HOME']


def do_su(r):
    frob_autocomplete='''
_frob() {
    case $COMP_CWORD in
        1) COMPREPLY=( $(compgen -W "$(frob complete)" "${COMP_WORDS[COMP_CWORD]}") ) ;;
        *) COMPREPLY=( $(compgen -fd "${COMP_WORDS[COMP_CWORD]}" ) );;
    esac
}
complete -F _frob frob

'''
    import tempfile
    tmp=tempfile.NamedTemporaryFile("w")
    tmp.write( "PS1='\\u@\\h [\\w]\\$ '\n" )
    tmp.write( frob_autocomplete )
    tmp.flush()

    os.environ['DNS'] = r['DNS']
    os.environ['USERNAME'] = r['username']
    os.environ['OWNER'] = r['owner']
    os.environ['CONFDIR'] = '/usr/local/apache/conf/userdata/std/2/%(username)s/%(DNS)s' % r
    os.environ['USERDATA'] = '/var/cpanel/userdata/%(username)s/%(DNS)s' % r
    os.environ['USERFILE'] = r['cpfile']
    os.environ['SUSPENDED'] = r['suspended']

    os.system("bash --rcfile "+tmp.name+" -i")

def print_results(stuff):
    #if not sys.stdout.isatty() and sys.stderr.isatty():
    sys.stderr.write(stuff)

def search_apache_configs(domain):
    httpdconf_files = [ "/usr/local/apache/conf/httpd.conf", "/etc/httpd/conf/httpd.conf", '/etc/apache2/apache2.conf', ]  # random arb
    httpdconf_files.extend( glob.glob ("/etc/httpd/conf.d/*.conf") )   # centos style
    httpdconf_files.extend( glob.glob ("/etc/httpd/sites-enabled/*") ) # debian style
    for httpdconf_file in httpdconf_files:
        rc = searchhttpdconf(domain,httpdconf_file)
        if rc: return rc
    return rc

def searchhttpdconf(domain,httpdconf_file):
    'Find best match in httpd config file'
    bestindex=''
    bestdocumentroot=''
    for index,documentroot in iteratehttpdconf(domain, httpdconf_file):
        if bestindex=='' or index<bestindex:
            bestindex=index
            bestdocumentroot=documentroot
    return bestdocumentroot
        
def iteratehttpdconf(domain,httpdconf_file):
    if not os.path.exists(httpdconf_file): return 
    found = False
    fd = open(httpdconf_file,"r")
    # ServerName mobii.com
    # ServerAlias mobii.test.afrihost.com www.mobii.com
    # DocumentRoot /home/mobiiidu/public_html
    re_servername = re.compile(r"ServerName\s+(\S+)")
    re_serveralias = re.compile(r"ServerAlias\s+(.+)")
    re_documentroot = re.compile(r"DocumentRoot\s+(\S+)")
    re_vhost = re.compile(r"</VirtualHost>")
    documentroot=''
    ratings={}
    index=65535
    for line in fd:
        if re_vhost.search(line):
            if found and documentroot:
                yield index, documentroot
                index=65536
        for regex in (re_servername, re_serveralias):
            m = regex.search(line)
            if not m: continue
            i = m.group(1).find(domain)
            if i >= 0:
                found=1
                index=i

        m = re_documentroot.search(line)
        if m:
            documentroot=m.group(1)

def readcpfile(cpfile):
    'Read /var/cpanel/users/someone'
    r = {}
    if not os.path.isfile(cpfile):
        return r
    fd = open(cpfile,'r');
    for line in fd:
        bits=line.split('=',1)
        if len(bits)!=2: continue
        r[bits[0].strip()]=bits[1].strip()
    fd.close()
    return r
    
def searchuserdomains(domain):
    userdomains_file="/etc/userdomains"
    if not os.path.exists(userdomains_file): return ''

    besti=65535
    fd = open(userdomains_file,"r")
    candidate=''
    for line in fd:
        bits=line.strip().split()
        if len(bits)!=2: continue
        dom,user=tuple(bits)
        i= dom.strip().find(domain);
        if i>=0 and i<=besti:
            candidate=pwd.getpwnam(user.strip()).pw_dir+'/public_html';
            besti=i
            if i==0: break
    return candidate

def main():
    # /etc/httpd/conf/httpd.conf
    # /etc/userdomains
    if len(sys.argv)<1:
        sys.stderr.write("Usage: %s domain.com\n" % sys.argv[0])
        sys.stderr.write("Displays the 'cd' command to go to a web site or mail domain\n")
        sys.exit()

    wd='.'
    for domain in sys.argv[1:]:
        if domain.startswith('/') and os.path.exists(domain):
            wd=domain
            break
        wd = searchuserdomains(domain)
        if not wd:
            wd = search_apache_configs(domain)
        if not wd:
            sys.stderr.write("# %s not found\n" % domain)
            return 1

    uid = os.stat(wd).st_uid
    username = pwd.getpwuid(uid).pw_name
    cpfile = '/var/cpanel/users/'+username
    r = readcpfile(cpfile)
    r['cpfile']=cpfile
    r['username']=username
    r['owner'] = readcpfile('/var/cpanel/users/'+r.get('OWNER','')).get('CONTACTEMAIL','')
    r['suspended'] = r.get('SUSPENDED','')
    if r['suspended'] and r.get('SUSPENDTIME',''):
        r['suspended'] = "'" + time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(int(r['SUSPENDTIME'])))+"'"
    r['DNS'] = r.get('DNS','');
    os.chdir(wd)
    r['pwd'] = os.getcwd();

    print_results( (
        'cd %(pwd)s\n'
        '        DNS=%(DNS)s\n'
        '   USERNAME=%(username)s\n'
        '      OWNER=%(owner)s\n' 
        '    CONFDIR=/usr/local/apache/conf/userdata/std/2/%(username)s/%(DNS)s\n'
        '   USERDATA=/var/cpanel/userdata/%(username)s/%(DNS)s\n'
        '   USERFILE=%(cpfile)s\n'
        '  SUSPENDED=%(suspended)s\n'
        ) % r )

    create_ahs_user()
    droppriv(groups=['ahs'])
    if sys.stdout.isatty():
        do_su(r)
    

if __name__=="__main__":
    main()
