/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-10-28 17:59:38 UTC
  • Revision ID: belorn@tower-20071028175938-26b85eaa85b84771
Working client and server and password system

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