source: server/common/oursrc/whoisd/whoisd.tac @ 627

Last change on this file since 627 was 627, checked in by quentin, 14 years ago
Support LDAP vhosts in whois server
File size: 3.6 KB
Line 
1from twisted.application import internet, service
2from twisted.internet import protocol, reactor, defer
3from twisted.protocols import basic
4import ldap, ldap.filter
5import os, sys, pwd, glob
6
7class WhoisProtocol(basic.LineReceiver):
8    def lineReceived(self, hostname):
9        self.factory.getWhois(hostname
10        ).addErrback(lambda _: "Internal error in server"
11        ).addCallback(lambda m:
12                      (self.transport.write(m+"\r\n"),
13                       self.transport.loseConnection()))
14class WhoisFactory(protocol.ServerFactory):
15    protocol = WhoisProtocol
16    def __init__(self, vhostDir, ldap_URL, ldap_base):
17        self.vhostDir = vhostDir
18        self.ldap_URL = ldap_URL
19        self.ldap = ldap.initialize(self.ldap_URL)
20        self.ldap_base = ldap_base
21        self.vhosts = {}
22        self.rescanVhosts()
23    def rescanVhosts(self):
24        newVhosts = {}
25        for f in glob.iglob(os.path.join(self.vhostDir, "*.conf")):
26            locker = os.path.splitext(os.path.basename(f))[0]
27            newVhosts.update(self.parseApacheConf(file(f)))
28        self.vhosts = newVhosts
29        self.vhostTime = os.stat(self.vhostDir).st_mtime
30    def parseApacheConf(self, f):
31        vhosts = {}
32        hostnames = []
33        locker = None
34        docroot = None
35        for l in f:
36            parts = l.split()
37            if not parts: continue
38            command = parts.pop(0)
39            if command in ("ServerName", "ServerAlias"):
40                hostnames.extend(parts)
41            elif command in ("SuExecUserGroup",):
42                locker = parts[0]
43            elif command in ("DocumentRoot",):
44                docroot = parts[0]
45            elif command == "</VirtualHost>":
46                d = {'locker': locker, 'apacheDocumentRoot': docroot, 'apacheServerName': hostnames[0]}
47                for h in hostnames: vhosts[h] = d
48                hostnames = []
49                locker = None
50                docroot = None
51        return vhosts
52    def canonicalize(self, vhost):
53        vhost = vhost.lower().rstrip(".")
54        return vhost
55#        if vhost.endswith(".mit.edu"):
56#            return vhost
57#        else:
58#            return vhost + ".mit.edu"
59    def searchLDAP(self, vhost):
60        results = self.ldap.search_s(self.ldap_base, ldap.SCOPE_SUBTREE,
61            ldap.filter.filter_format(
62                '(|(apacheServername=%s)(apacheServerAlias=%s))', (vhost,)*2))
63        if len(results) >= 1:
64            result = results[0]
65            attrs = result[1]
66            for attr in ('apacheServerName','apacheDocumentRoot', 'apacheSuexecUid', 'apacheSuexecGid'):
67                attrs[attr] = attrs[attr][0]
68            user = pwd.getpwuid(int(attrs['apacheSuexecUid']))
69            if user:
70                attrs['locker'] = user.pw_name
71            else:
72                attrs['locker'] = None
73            return attrs
74        else:
75            return None
76    def getWhois(self, vhost):
77        vhost = self.canonicalize(vhost)
78        info = self.vhosts.get(vhost)
79        if not info:
80            info = self.searchLDAP(vhost)
81        if info:
82            ret = "Hostname: %s\nAlias: %s\nLocker: %s\nDocument Root: %s" % \
83                (info['apacheServerName'], vhost, info['locker'], info['apacheDocumentRoot'])
84        else:
85            ret = "No such hostname"
86        return defer.succeed(ret)
87
88application = service.Application('whois', uid=99, gid=99)
89factory = WhoisFactory("/etc/httpd/vhosts.d",
90    "ldap://localhost", "ou=VirtualHosts,dc=scripts,dc=mit,dc=edu")
91internet.TCPServer(43, factory).setServiceParent(
92    service.IServiceCollection(application))
Note: See TracBrowser for help on using the repository browser.