src/mercurialserver/refreshauth.py
author Paul Crowley <paul@lshift.net>
Fri, 06 Mar 2009 13:30:37 +0000
changeset 78 2a3407a14654
parent 75 5af89523a9d3
child 79 3a58a95fae2f
permissions -rw-r--r--
Replaced env vars with Python globals

# Copyright 2008-2009 LShift Ltd

# WARNING
# This hook completely destroys your ~/.ssh/authorized_keys
# file every time it is run
# WARNING

import sys
import os
import os.path
import pwd
import subprocess
from mercurialserver import ruleset, paths

def refreshAuth():
    pentry = pwd.getpwuid(os.geteuid())
    if pentry.pw_name != "hg":
        # FIXME: re-execute
        print >>sys.stderr, "Must be run as the 'hg' user"

    akeyfile = pentry.pw_dir + "/.ssh/authorized_keys"
    wrappercommand = paths.getEtcPath() + "/hg-ssh-wrapper"
    keydirs = [paths.getEtcPath() + "/keys", pentry.pw_dir + "/repos/hgadmin/keys"]
    prefix='no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command='

    if os.path.exists(akeyfile):
        f = open(akeyfile)
        try:
            for l in f:
                if not l.startswith(prefix):
                    raise Exception("Safety check failed, delete %s to continue" % akeyfile)
        finally:
            f.close()

    akeys = open(akeyfile + "_new", "w")
    for keyroot in keydirs:
        kr = keyroot + "/"
        #print "Processing keyroot", keyroot
        for root, dirs, files in os.walk(keyroot):
            for fn in files:
                ffn = os.path.join(root, fn)
                if not ffn.startswith(kr):
                    raise Exception("Inconsistent behaviour in os.walk, bailing")
                #print "Processing file", ffn
                keyname = ffn[len(kr):]
                if not ruleset.goodpath(keyname):
                    # ignore any path that contains dodgy characters
                    #print "Ignoring file", ffn
                    continue
                p = subprocess.Popen(("ssh-keygen", "-i", "-f", ffn), 
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                newkey = p.communicate()[0]
                if p.wait() == 0:
                    klines = [l.strip() for l in newkey.split("\n")]
                else:
                    # Conversion failed, read it directly.
                    kf = open(ffn)
                    try:
                        klines = [l.strip() for l in kf]
                    finally:
                        kf.close()
                for l in klines:
                    if len(l):
                        akeys.write('%s"%s %s" %s\n' % (prefix, wrappercommand, keyname, l))

    akeys.close()

    os.rename(akeyfile + "_new", akeyfile)
    
def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
    refreshAuth()