/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: Teddy Hogeborn
  • Date: 2008-01-18 22:04:19 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080118220419-z95418owrporioo5
* Makefile (client_debug): New.
* client.cpp (CERT_ROOT): New.

(Tested)

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
import gnutls.connection
11
11
import gnutls.errors
12
12
import ConfigParser
 
13
import sys
 
14
 
13
15
 
14
16
class Client(object):
15
 
    def __init__(self, name=None, dn=None, password=None,
16
 
                 passfile=None, fqdn=None, timeout=None,
17
 
                 interval=-1):
 
17
    def __init__(self, name=None, options=None, dn=None,
 
18
                 password=None, passfile=None, fqdn=None,
 
19
                 timeout=None, interval=-1):
18
20
        self.name = name
19
21
        self.dn = dn
20
22
        if password:
26
28
            # raise RuntimeError XXX
27
29
            self.password = "gazonk"
28
30
        self.fqdn = fqdn
29
 
        # self.created = ...
 
31
        self.created = datetime.datetime.now()
30
32
        self.last_seen = None
31
33
        if timeout is None:
32
 
            timeout = self.server.options.timeout
 
34
            timeout = options.timeout
33
35
        self.timeout = timeout
34
36
        if interval == -1:
35
 
            interval = self.server.options.interval
 
37
            interval = options.interval
36
38
        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)
 
39
        self.next_check = datetime.datetime.now()
 
40
 
 
41
 
 
42
class server_metaclass(type):
 
43
    "Common behavior for the UDP and TCP server classes"
 
44
    def __new__(cls, name, bases, attrs):
 
45
        attrs["address_family"] = socket.AF_INET6
 
46
        attrs["allow_reuse_address"] = True
 
47
        def server_bind(self):
 
48
            if self.options.interface:
 
49
                if not hasattr(socket, "SO_BINDTODEVICE"):
 
50
                    # From /usr/include/asm-i486/socket.h
 
51
                    socket.SO_BINDTODEVICE = 25
 
52
                try:
 
53
                    self.socket.setsockopt(socket.SOL_SOCKET,
 
54
                                           socket.SO_BINDTODEVICE,
 
55
                                           self.options.interface)
 
56
                except socket.error, error:
 
57
                    if error[0] == errno.EPERM:
 
58
                        print "Warning: No permission to bind to interface", \
 
59
                              self.options.interface
 
60
                    else:
 
61
                        raise error
 
62
            return super(type(self), self).server_bind()
 
63
        attrs["server_bind"] = server_bind
 
64
        def init(self, *args, **kwargs):
 
65
            if "options" in kwargs:
 
66
                self.options = kwargs["options"]
 
67
                del kwargs["options"]
 
68
            if "clients" in kwargs:
 
69
                self.clients = kwargs["clients"]
 
70
                del kwargs["clients"]
 
71
            if "credentials" in kwargs:
 
72
                self.credentials = kwargs["credentials"]
 
73
                del kwargs["credentials"]
 
74
            return super(type(self), self).__init__(*args, **kwargs)
 
75
        attrs["__init__"] = init
 
76
        return type.__new__(cls, name, bases, attrs)
67
77
 
68
78
 
69
79
class udp_handler(SocketServer.DatagramRequestHandler, object):
73
83
 
74
84
 
75
85
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
 
86
    __metaclass__ = server_metaclass
80
87
    def verify_request(self, request, client_address):
81
88
        print "UDP request came"
82
89
        return request[0] == "Marco"
108
115
            # Log maybe? XXX
109
116
        session.bye()
110
117
 
 
118
 
111
119
class IPv6_TCPServer(SocketServer.ForkingTCPServer, object):
112
 
    __init__ = init_with_options
113
 
    address_family = socket.AF_INET6
114
 
    allow_reuse_address = True
 
120
    __metaclass__ = server_metaclass
115
121
    request_queue_size = 1024
116
 
    server_bind = server_bind
117
122
 
118
123
 
119
124
in6addr_any = "::"
120
125
 
121
126
cred = None
122
127
 
 
128
def string_to_delta(interval):
 
129
    """Parse a string and return a datetime.timedelta
 
130
 
 
131
    >>> string_to_delta('7d')
 
132
    datetime.timedelta(7)
 
133
    >>> string_to_delta('60s')
 
134
    datetime.timedelta(0, 60)
 
135
    >>> string_to_delta('60m')
 
136
    datetime.timedelta(0, 3600)
 
137
    >>> string_to_delta('24h')
 
138
    datetime.timedelta(1)
 
139
    >>> string_to_delta(u'1w')
 
140
    datetime.timedelta(7)
 
141
    """
 
142
    try:
 
143
        suffix=unicode(interval[-1])
 
144
        value=int(interval[:-1])
 
145
        if suffix == u"d":
 
146
            delta = datetime.timedelta(value)
 
147
        elif suffix == u"s":
 
148
            delta = datetime.timedelta(0, value)
 
149
        elif suffix == u"m":
 
150
            delta = datetime.timedelta(0, 0, 0, 0, value)
 
151
        elif suffix == u"h":
 
152
            delta = datetime.timedelta(0, 0, 0, 0, 0, value)
 
153
        elif suffix == u"w":
 
154
            delta = datetime.timedelta(0, 0, 0, 0, 0, 0, value)
 
155
        else:
 
156
            raise ValueError
 
157
    except (ValueError, IndexError):
 
158
        raise ValueError
 
159
    return delta
 
160
 
123
161
def main():
124
162
    parser = OptionParser()
125
163
    parser.add_option("-i", "--interface", type="string",
144
182
    parser.add_option("-t", "--timeout", type="string", # Parsed later
145
183
                      default="15m",
146
184
                      help="Amount of downtime allowed for clients")
 
185
    parser.add_option("--interval", type="string", # Parsed later
 
186
                      default="5m",
 
187
                      help="How often to check that a client is up")
 
188
    parser.add_option("--check", action="store_true", default=False,
 
189
                      help="Run self-test")
147
190
    (options, args) = parser.parse_args()
 
191
 
 
192
    if options.check:
 
193
        import doctest
 
194
        doctest.testmod()
 
195
        sys.exit()
148
196
    
149
 
    # Parse the time argument
 
197
    # Parse the time arguments
150
198
    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):
 
199
        options.timeout = string_to_delta(options.timeout)
 
200
    except ValueError:
167
201
        parser.error("option --timeout: Unparseable time")
168
202
    
 
203
    try:
 
204
        options.interval = string_to_delta(options.interval)
 
205
    except ValueError:
 
206
        parser.error("option --interval: Unparseable time")
 
207
    
169
208
    cert = gnutls.crypto.X509Certificate(open(options.cert).read())
170
209
    key = gnutls.crypto.X509PrivateKey(open(options.key).read())
171
210
    ca = gnutls.crypto.X509Certificate(open(options.ca).read())
176
215
    defaults = {}
177
216
    client_config_object = ConfigParser.SafeConfigParser(defaults)
178
217
    client_config_object.read("mandos-clients.conf")
179
 
    clients = [Client(name=section,
 
218
    clients = [Client(name=section, options=options,
180
219
                      **(dict(client_config_object.items(section))))
181
220
               for section in client_config_object.sections()]
182
221