/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to server.py

  • Committer: Björn Påhlsson
  • Date: 2007-12-11 23:40:35 UTC
  • Revision ID: belorn@braxen-20071211234035-m1nsu41vuzkak69h
Python based server
Added client configfile

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
 
 
3
import SocketServer
 
4
import socket
 
5
import select
 
6
from optparse import OptionParser
 
7
import datetime
 
8
import errno
 
9
import gnutls.crypto
 
10
import gnutls.connection
 
11
import gnutls.errors
 
12
import ConfigParser
 
13
 
 
14
class Client(object):
 
15
    def __init__(self, name=None, dn=None, password=None,
 
16
                 passfile=None, fqdn=None, timeout=None,
 
17
                 interval=-1):
 
18
        self.name = name
 
19
        self.dn = dn
 
20
        if password:
 
21
            self.password = password
 
22
        elif passfile:
 
23
            self.password = open(passfile).readall()
 
24
        else:
 
25
            print "No Password or Passfile in client config file"
 
26
            # raise RuntimeError XXX
 
27
            self.password = "gazonk"
 
28
        self.fqdn = fqdn
 
29
        # self.created = ...
 
30
        self.last_seen = None
 
31
        if timeout is None:
 
32
            timeout = self.server.options.timeout
 
33
        self.timeout = timeout
 
34
        if interval == -1:
 
35
            interval = self.server.options.interval
 
36
        self.interval = interval
 
37
 
 
38
def server_bind(self):
 
39
    if self.options.interface:
 
40
        if not hasattr(socket, "SO_BINDTODEVICE"):
 
41
            # From /usr/include/asm-i486/socket.h
 
42
            socket.SO_BINDTODEVICE = 25
 
43
        try:
 
44
            self.socket.setsockopt(socket.SOL_SOCKET,
 
45
                                   socket.SO_BINDTODEVICE,
 
46
                                   self.options.interface)
 
47
        except socket.error, error:
 
48
            if error[0] == errno.EPERM:
 
49
                print "Warning: Denied permission to bind to interface", \
 
50
                      self.options.interface
 
51
            else:
 
52
                raise error
 
53
    return super(type(self), self).server_bind()
 
54
 
 
55
 
 
56
def init_with_options(self, *args, **kwargs):
 
57
    if "options" in kwargs:
 
58
        self.options = kwargs["options"]
 
59
        del kwargs["options"]
 
60
    if "clients" in kwargs:
 
61
        self.clients = kwargs["clients"]
 
62
        del kwargs["clients"]
 
63
    if "credentials" in kwargs:
 
64
        self.credentials = kwargs["credentials"]
 
65
        del kwargs["credentials"]
 
66
    return super(type(self), self).__init__(*args, **kwargs)
 
67
 
 
68
 
 
69
class udp_handler(SocketServer.DatagramRequestHandler, object):
 
70
    def handle(self):
 
71
        self.wfile.write("Polo")
 
72
        print "UDP request answered"
 
73
 
 
74
 
 
75
class IPv6_UDPServer(SocketServer.UDPServer, object):
 
76
    __init__ = init_with_options
 
77
    address_family = socket.AF_INET6
 
78
    allow_reuse_address = True
 
79
    server_bind = server_bind
 
80
    def verify_request(self, request, client_address):
 
81
        print "UDP request came"
 
82
        return request[0] == "Marco"
 
83
 
 
84
 
 
85
class tcp_handler(SocketServer.BaseRequestHandler, object):
 
86
    def handle(self):
 
87
        print "TCP request came"
 
88
        print "Request:", self.request
 
89
        print "Client Address:", self.client_address
 
90
        print "Server:", self.server
 
91
        session = gnutls.connection.ServerSession(self.request,
 
92
                                                  self.server.credentials)
 
93
        session.handshake()
 
94
        if session.peer_certificate:
 
95
            print "DN:", session.peer_certificate.subject
 
96
        try:
 
97
            session.verify_peer()
 
98
        except gnutls.errors.CertificateError, error:
 
99
            print "Verify failed", error
 
100
            session.bye()
 
101
            return
 
102
        try:
 
103
            session.send(dict((client.dn, client.password)
 
104
                              for client in self.server.clients)
 
105
                         [session.peer_certificate.subject])
 
106
        except KeyError:
 
107
            session.send("gazonk")
 
108
            # Log maybe? XXX
 
109
        session.bye()
 
110
 
 
111
class IPv6_TCPServer(SocketServer.ForkingTCPServer, object):
 
112
    __init__ = init_with_options
 
113
    address_family = socket.AF_INET6
 
114
    allow_reuse_address = True
 
115
    request_queue_size = 1024
 
116
    server_bind = server_bind
 
117
 
 
118
 
 
119
in6addr_any = "::"
 
120
 
 
121
cred = None
 
122
 
 
123
def main():
 
124
    parser = OptionParser()
 
125
    parser.add_option("-i", "--interface", type="string",
 
126
                      default="eth0", metavar="IF",
 
127
                      help="Interface to bind to")
 
128
    parser.add_option("--cert", type="string", default="cert.pem",
 
129
                      metavar="FILE",
 
130
                      help="Public key certificate to use")
 
131
    parser.add_option("--key", type="string", default="key.pem",
 
132
                      metavar="FILE",
 
133
                      help="Private key to use")
 
134
    parser.add_option("--ca", type="string", default="ca.pem",
 
135
                      metavar="FILE",
 
136
                      help="Certificate Authority certificate to use")
 
137
    parser.add_option("--crl", type="string", default="crl.pem",
 
138
                      metavar="FILE",
 
139
                      help="Certificate Revokation List to use")
 
140
    parser.add_option("-p", "--port", type="int", default=49001,
 
141
                      help="Port number to receive requests on")
 
142
    parser.add_option("--dh", type="int", metavar="BITS",
 
143
                      help="DH group to use")
 
144
    parser.add_option("-t", "--timeout", type="string", # Parsed later
 
145
                      default="15m",
 
146
                      help="Amount of downtime allowed for clients")
 
147
    (options, args) = parser.parse_args()
 
148
    
 
149
    # Parse the time argument
 
150
    try:
 
151
        suffix=options.timeout[-1]
 
152
        value=int(options.timeout[:-1])
 
153
        if suffix == "d":
 
154
            options.timeout = datetime.timedelta(value)
 
155
        elif suffix == "s":
 
156
            options.timeout = datetime.timedelta(0, value)
 
157
        elif suffix == "m":
 
158
            options.timeout = datetime.timedelta(0, 0, 0, 0, value)
 
159
        elif suffix == "h":
 
160
            options.timeout = datetime.timedelta(0, 0, 0, 0, 0, value)
 
161
        elif suffix == "w":
 
162
            options.timeout = datetime.timedelta(0, 0, 0, 0, 0, 0,
 
163
                                                 value)
 
164
        else:
 
165
            raise ValueError
 
166
    except (ValueError, IndexError):
 
167
        parser.error("option --timeout: Unparseable time")
 
168
    
 
169
    cert = gnutls.crypto.X509Certificate(open(options.cert).read())
 
170
    key = gnutls.crypto.X509PrivateKey(open(options.key).read())
 
171
    ca = gnutls.crypto.X509Certificate(open(options.ca).read())
 
172
    crl = gnutls.crypto.X509CRL(open(options.crl).read())
 
173
    cred = gnutls.connection.X509Credentials(cert, key, [ca], [crl])
 
174
    
 
175
    # Parse config file
 
176
    defaults = {}
 
177
    client_config_object = ConfigParser.SafeConfigParser(defaults)
 
178
    client_config_object.read("mandos-clients.conf")
 
179
    clients = [Client(name=section,
 
180
                      **(dict(client_config_object.items(section))))
 
181
               for section in client_config_object.sections()]
 
182
    
 
183
    udp_server = IPv6_UDPServer((in6addr_any, options.port),
 
184
                                udp_handler,
 
185
                                options=options)
 
186
    
 
187
    tcp_server = IPv6_TCPServer((in6addr_any, options.port),
 
188
                                tcp_handler,
 
189
                                options=options,
 
190
                                clients=clients,
 
191
                                credentials=cred)
 
192
    
 
193
    while True:
 
194
        in_, out, err = select.select((udp_server,
 
195
                                       tcp_server), (), ())
 
196
        for server in in_:
 
197
            server.handle_request()
 
198
 
 
199
 
 
200
if __name__ == "__main__":
 
201
    main()
 
202