/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk
3 by Björn Påhlsson
Python based server
1
#!/usr/bin/python
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
2
# -*- mode: python; coding: utf-8 -*-
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
3
# 
4
# Mandos server - give out binary blobs to connecting clients.
5
# 
6
# This program is partly derived from an example program for an Avahi
7
# service publisher, downloaded from
8
# <http://avahi.org/wiki/PythonPublishExample>.  This includes the
46 by Teddy Hogeborn
* network-protocol.txt: New.
9
# methods "add" and "remove" in the "AvahiService" class, the
10
# "server_state_changed" and "entry_group_state_changed" functions,
11
# and some lines in "main".
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
12
# 
28 by Teddy Hogeborn
* server.conf: New file.
13
# Everything else is
246 by Teddy Hogeborn
* README: Update copyright year; add "2009".
14
# Copyright © 2008,2009 Teddy Hogeborn
15
# Copyright © 2008,2009 Björn Påhlsson
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
16
# 
17
# This program is free software: you can redistribute it and/or modify
18
# it under the terms of the GNU General Public License as published by
19
# the Free Software Foundation, either version 3 of the License, or
20
# (at your option) any later version.
21
#
22
#     This program is distributed in the hope that it will be useful,
23
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
24
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
#     GNU General Public License for more details.
26
# 
27
# You should have received a copy of the GNU General Public License
109 by Teddy Hogeborn
* .bzrignore: New.
28
# along with this program.  If not, see
29
# <http://www.gnu.org/licenses/>.
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
30
# 
28 by Teddy Hogeborn
* server.conf: New file.
31
# Contact the authors at <mandos@fukt.bsnet.se>.
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
32
# 
3 by Björn Påhlsson
Python based server
33
237 by Teddy Hogeborn
* mandos: Also import "with_statement" and "absolute_import" from
34
from __future__ import division, with_statement, absolute_import
10 by Teddy Hogeborn
* server.py: Bug fix: Do "from __future__ import division".
35
3 by Björn Påhlsson
Python based server
36
import SocketServer
37
import socket
237.2.1 by Teddy Hogeborn
Merge from trunk, but disable the unfinished D-Bus feature:
38
import optparse
3 by Björn Påhlsson
Python based server
39
import datetime
40
import errno
41
import gnutls.crypto
42
import gnutls.connection
43
import gnutls.errors
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
44
import gnutls.library.functions
45
import gnutls.library.constants
46
import gnutls.library.types
3 by Björn Påhlsson
Python based server
47
import ConfigParser
4 by Teddy Hogeborn
* server.py (Client.created, Client.next_check): New.
48
import sys
9 by Teddy Hogeborn
* client.cpp (main): Get t_old early since it is used on error exits.
49
import re
50
import os
51
import signal
10 by Teddy Hogeborn
* server.py: Bug fix: Do "from __future__ import division".
52
from sets import Set
53
import subprocess
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
54
import atexit
55
import stat
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
56
import logging
57
import logging.handlers
163 by Teddy Hogeborn
* Makefile (PIDDIR, USER, GROUP): Removed.
58
import pwd
237 by Teddy Hogeborn
* mandos: Also import "with_statement" and "absolute_import" from
59
from contextlib import closing
5 by Teddy Hogeborn
* server.py (server_metaclass): New.
60
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
61
import dbus
237.1.1 by Teddy Hogeborn
First steps of a D-Bus interface to the server.
62
import dbus.service
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
63
import gobject
64
import avahi
65
from dbus.mainloop.glib import DBusGMainLoop
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
66
import ctypes
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
67
import ctypes.util
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
68
237.2.18 by Teddy Hogeborn
* Makefile (version): Changed to "1.0.8".
69
version = "1.0.8"
13 by Björn Påhlsson
Added following support:
70
71
logger = logging.Logger('mandos')
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
72
syslogger = (logging.handlers.SysLogHandler
73
             (facility = logging.handlers.SysLogHandler.LOG_DAEMON,
74
              address = "/dev/log"))
75
syslogger.setFormatter(logging.Formatter
292 by Teddy Hogeborn
* Makefile (run-server): Use "--no-dbus" unconditionally.
76
                       ('Mandos [%(process)d]: %(levelname)s:'
77
                        ' %(message)s'))
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
78
logger.addHandler(syslogger)
13 by Björn Påhlsson
Added following support:
79
61 by Teddy Hogeborn
* mandos (console): Define handler globally.
80
console = logging.StreamHandler()
292 by Teddy Hogeborn
* Makefile (run-server): Use "--no-dbus" unconditionally.
81
console.setFormatter(logging.Formatter('%(name)s [%(process)d]:'
82
                                       ' %(levelname)s: %(message)s'))
61 by Teddy Hogeborn
* mandos (console): Define handler globally.
83
logger.addHandler(console)
28 by Teddy Hogeborn
* server.conf: New file.
84
85
class AvahiError(Exception):
242 by Teddy Hogeborn
* mandos (AvahiError): Converted to use unicode. All users changed.
86
    def __init__(self, value, *args, **kwargs):
28 by Teddy Hogeborn
* server.conf: New file.
87
        self.value = value
242 by Teddy Hogeborn
* mandos (AvahiError): Converted to use unicode. All users changed.
88
        super(AvahiError, self).__init__(value, *args, **kwargs)
89
    def __unicode__(self):
90
        return unicode(repr(self.value))
28 by Teddy Hogeborn
* server.conf: New file.
91
92
class AvahiServiceError(AvahiError):
93
    pass
94
95
class AvahiGroupError(AvahiError):
96
    pass
97
98
99
class AvahiService(object):
45 by Teddy Hogeborn
* server.py: Cosmetic changes.
100
    """An Avahi (Zeroconf) service.
101
    Attributes:
28 by Teddy Hogeborn
* server.conf: New file.
102
    interface: integer; avahi.IF_UNSPEC or an interface index.
103
               Used to optionally bind to the specified interface.
45 by Teddy Hogeborn
* server.py: Cosmetic changes.
104
    name: string; Example: 'Mandos'
105
    type: string; Example: '_mandos._tcp'.
106
                  See <http://www.dns-sd.org/ServiceTypes.html>
107
    port: integer; what port to announce
108
    TXT: list of strings; TXT record for the service
109
    domain: string; Domain to publish on, default to .local if empty.
110
    host: string; Host to publish records for, default is localhost
111
    max_renames: integer; maximum number of renames
112
    rename_count: integer; counter so we only rename after collisions
113
                  a sensible number of times
28 by Teddy Hogeborn
* server.conf: New file.
114
    """
115
    def __init__(self, interface = avahi.IF_UNSPEC, name = None,
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
116
                 servicetype = None, port = None, TXT = None,
314 by Teddy Hogeborn
Support not using IPv6 in server:
117
                 domain = "", host = "", max_renames = 32768,
118
                 protocol = avahi.PROTO_UNSPEC):
28 by Teddy Hogeborn
* server.conf: New file.
119
        self.interface = interface
120
        self.name = name
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
121
        self.type = servicetype
28 by Teddy Hogeborn
* server.conf: New file.
122
        self.port = port
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
123
        self.TXT = TXT if TXT is not None else []
28 by Teddy Hogeborn
* server.conf: New file.
124
        self.domain = domain
125
        self.host = host
126
        self.rename_count = 0
76 by Teddy Hogeborn
* plugins.d/password-request.c (init_gnutls_global): Renamed
127
        self.max_renames = max_renames
314 by Teddy Hogeborn
Support not using IPv6 in server:
128
        self.protocol = protocol
28 by Teddy Hogeborn
* server.conf: New file.
129
    def rename(self):
130
        """Derived from the Avahi example code"""
131
        if self.rename_count >= self.max_renames:
109 by Teddy Hogeborn
* .bzrignore: New.
132
            logger.critical(u"No suitable Zeroconf service name found"
133
                            u" after %i retries, exiting.",
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
134
                            self.rename_count)
242 by Teddy Hogeborn
* mandos (AvahiError): Converted to use unicode. All users changed.
135
            raise AvahiServiceError(u"Too many renames")
76 by Teddy Hogeborn
* plugins.d/password-request.c (init_gnutls_global): Renamed
136
        self.name = server.GetAlternativeServiceName(self.name)
109 by Teddy Hogeborn
* .bzrignore: New.
137
        logger.info(u"Changing Zeroconf service name to %r ...",
138
                    str(self.name))
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
139
        syslogger.setFormatter(logging.Formatter
327 by Teddy Hogeborn
Merge from pipe IPC branch.
140
                               ('Mandos (%s) [%%(process)d]:'
141
                                ' %%(levelname)s: %%(message)s'
142
                                % self.name))
28 by Teddy Hogeborn
* server.conf: New file.
143
        self.remove()
144
        self.add()
145
        self.rename_count += 1
146
    def remove(self):
147
        """Derived from the Avahi example code"""
148
        if group is not None:
149
            group.Reset()
150
    def add(self):
151
        """Derived from the Avahi example code"""
152
        global group
153
        if group is None:
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
154
            group = dbus.Interface(bus.get_object
155
                                   (avahi.DBUS_NAME,
28 by Teddy Hogeborn
* server.conf: New file.
156
                                    server.EntryGroupNew()),
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
157
                                   avahi.DBUS_INTERFACE_ENTRY_GROUP)
28 by Teddy Hogeborn
* server.conf: New file.
158
            group.connect_to_signal('StateChanged',
159
                                    entry_group_state_changed)
109 by Teddy Hogeborn
* .bzrignore: New.
160
        logger.debug(u"Adding Zeroconf service '%s' of type '%s' ...",
28 by Teddy Hogeborn
* server.conf: New file.
161
                     service.name, service.type)
162
        group.AddService(
163
                self.interface,         # interface
314 by Teddy Hogeborn
Support not using IPv6 in server:
164
                self.protocol,          # protocol
28 by Teddy Hogeborn
* server.conf: New file.
165
                dbus.UInt32(0),         # flags
166
                self.name, self.type,
167
                self.domain, self.host,
168
                dbus.UInt16(self.port),
169
                avahi.string_array_to_txt_array(self.TXT))
170
        group.Commit()
171
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
172
# From the Avahi example code:
28 by Teddy Hogeborn
* server.conf: New file.
173
group = None                            # our entry group
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
174
# End of Avahi example code
175
176
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
177
def _datetime_to_dbus(dt, variant_level=0):
178
    """Convert a UTC datetime.datetime() to a D-Bus type."""
179
    return dbus.String(dt.isoformat(), variant_level=variant_level)
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
180
181
237.1.1 by Teddy Hogeborn
First steps of a D-Bus interface to the server.
182
class Client(dbus.service.Object):
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
183
    """A representation of a client host served by this server.
184
    Attributes:
278 by Teddy Hogeborn
* mandos (Client.GetAllProperties): Also send Client.dbus_object_path
185
    name:       string; from the config file, used in log messages and
186
                        D-Bus identifiers
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
187
    fingerprint: string (40 or 32 hexadecimal digits); used to
188
                 uniquely identify the client
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
189
    secret:     bytestring; sent verbatim (over TLS) to client
190
    host:       string; available for use by the checker command
191
    created:    datetime.datetime(); (UTC) object creation
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
192
    last_enabled: datetime.datetime(); (UTC)
193
    enabled:    bool()
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
194
    last_checked_ok: datetime.datetime(); (UTC) or None
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
195
    timeout:    datetime.timedelta(); How long from last_checked_ok
196
                                      until this client is invalid
197
    interval:   datetime.timedelta(); How often to start a new checker
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
198
    disable_hook:  If set, called by disable() as disable_hook(self)
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
199
    checker:    subprocess.Popen(); a running checker process used
200
                                    to see if the client lives.
201
                                    'None' if no process is running.
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
202
    checker_initiator_tag: a gobject event source tag, or None
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
203
    disable_initiator_tag:    - '' -
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
204
    checker_callback_tag:  - '' -
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
205
    checker_command: string; External command which is run to check if
28 by Teddy Hogeborn
* server.conf: New file.
206
                     client lives.  %() expansions are done at
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
207
                     runtime with vars(self) as dict, so that for
208
                     instance %(name)s can be used in the command.
315 by Teddy Hogeborn
* mandos (Client.current_checker_command): New attribute.
209
    current_checker_command: string; current running checker_command
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
210
    use_dbus: bool(); Whether to provide D-Bus interface and signals
211
    dbus_object_path: dbus.ObjectPath ; only set if self.use_dbus
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
212
    """
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
213
    def timeout_milliseconds(self):
214
        "Return the 'timeout' attribute in milliseconds"
215
        return ((self.timeout.days * 24 * 60 * 60 * 1000)
216
                + (self.timeout.seconds * 1000)
217
                + (self.timeout.microseconds // 1000))
218
    
219
    def interval_milliseconds(self):
220
        "Return the 'interval' attribute in milliseconds"
221
        return ((self.interval.days * 24 * 60 * 60 * 1000)
222
                + (self.interval.seconds * 1000)
223
                + (self.interval.microseconds // 1000))
224
    
225
    def __init__(self, name = None, disable_hook=None, config=None,
226
                 use_dbus=True):
45 by Teddy Hogeborn
* server.py: Cosmetic changes.
227
        """Note: the 'checker' key in 'config' sets the
228
        'checker_command' attribute and *not* the 'checker'
229
        attribute."""
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
230
        self.name = name
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
231
        if config is None:
232
            config = {}
25 by Teddy Hogeborn
* mandos-clients.conf ([DEFAULT]): New section.
233
        logger.debug(u"Creating client %r", self.name)
279 by Teddy Hogeborn
* mandos (Client.__init__): Disable D-Bus during init to avoid
234
        self.use_dbus = False   # During __init__
45 by Teddy Hogeborn
* server.py: Cosmetic changes.
235
        # Uppercase and remove spaces from fingerprint for later
236
        # comparison purposes with return value from the fingerprint()
237
        # function
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
238
        self.fingerprint = (config["fingerprint"].upper()
239
                            .replace(u" ", u""))
25 by Teddy Hogeborn
* mandos-clients.conf ([DEFAULT]): New section.
240
        logger.debug(u"  Fingerprint: %s", self.fingerprint)
44 by Teddy Hogeborn
* ca.pem: Removed.
241
        if "secret" in config:
242
            self.secret = config["secret"].decode(u"base64")
243
        elif "secfile" in config:
237 by Teddy Hogeborn
* mandos: Also import "with_statement" and "absolute_import" from
244
            with closing(open(os.path.expanduser
245
                              (os.path.expandvars
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
246
                               (config["secfile"])))) as secfile:
237 by Teddy Hogeborn
* mandos: Also import "with_statement" and "absolute_import" from
247
                self.secret = secfile.read()
3 by Björn Påhlsson
Python based server
248
        else:
28 by Teddy Hogeborn
* server.conf: New file.
249
            raise TypeError(u"No secret or secfile for client %s"
250
                            % self.name)
51 by Teddy Hogeborn
* clients.conf: Better comments.
251
        self.host = config.get("host", "")
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
252
        self.created = datetime.datetime.utcnow()
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
253
        self.enabled = False
254
        self.last_enabled = None
28 by Teddy Hogeborn
* server.conf: New file.
255
        self.last_checked_ok = None
44 by Teddy Hogeborn
* ca.pem: Removed.
256
        self.timeout = string_to_delta(config["timeout"])
257
        self.interval = string_to_delta(config["interval"])
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
258
        self.disable_hook = disable_hook
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
259
        self.checker = None
260
        self.checker_initiator_tag = None
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
261
        self.disable_initiator_tag = None
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
262
        self.checker_callback_tag = None
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
263
        self.checker_command = config["checker"]
315 by Teddy Hogeborn
* mandos (Client.current_checker_command): New attribute.
264
        self.current_checker_command = None
279 by Teddy Hogeborn
* mandos (Client.__init__): Disable D-Bus during init to avoid
265
        self.last_connect = None
266
        # Only now, when this client is initialized, can it show up on
267
        # the D-Bus
268
        self.use_dbus = use_dbus
269
        if self.use_dbus:
270
            self.dbus_object_path = (dbus.ObjectPath
271
                                     ("/clients/"
272
                                      + self.name.replace(".", "_")))
273
            dbus.service.Object.__init__(self, bus,
274
                                         self.dbus_object_path)
237.1.1 by Teddy Hogeborn
First steps of a D-Bus interface to the server.
275
    
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
276
    def enable(self):
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
277
        """Start this client's checker and timeout hooks"""
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
278
        self.last_enabled = datetime.datetime.utcnow()
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
279
        # Schedule a new checker to be started an 'interval' from now,
280
        # and every interval from then on.
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
281
        self.checker_initiator_tag = (gobject.timeout_add
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
282
                                      (self.interval_milliseconds(),
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
283
                                       self.start_checker))
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
284
        # Also start a new checker *right now*.
285
        self.start_checker()
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
286
        # Schedule a disable() when 'timeout' has passed
287
        self.disable_initiator_tag = (gobject.timeout_add
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
288
                                   (self.timeout_milliseconds(),
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
289
                                    self.disable))
290
        self.enabled = True
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
291
        if self.use_dbus:
292
            # Emit D-Bus signals
293
            self.PropertyChanged(dbus.String(u"enabled"),
294
                                 dbus.Boolean(True, variant_level=1))
295
            self.PropertyChanged(dbus.String(u"last_enabled"),
296
                                 (_datetime_to_dbus(self.last_enabled,
297
                                                    variant_level=1)))
237.1.1 by Teddy Hogeborn
First steps of a D-Bus interface to the server.
298
    
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
299
    def disable(self):
300
        """Disable this client."""
301
        if not getattr(self, "enabled", False):
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
302
            return False
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
303
        logger.info(u"Disabling client %s", self.name)
304
        if getattr(self, "disable_initiator_tag", False):
305
            gobject.source_remove(self.disable_initiator_tag)
306
            self.disable_initiator_tag = None
28 by Teddy Hogeborn
* server.conf: New file.
307
        if getattr(self, "checker_initiator_tag", False):
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
308
            gobject.source_remove(self.checker_initiator_tag)
309
            self.checker_initiator_tag = None
310
        self.stop_checker()
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
311
        if self.disable_hook:
312
            self.disable_hook(self)
313
        self.enabled = False
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
314
        if self.use_dbus:
315
            # Emit D-Bus signal
316
            self.PropertyChanged(dbus.String(u"enabled"),
317
                                 dbus.Boolean(False, variant_level=1))
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
318
        # Do not run this again if called by a gobject.timeout_add
319
        return False
237.1.1 by Teddy Hogeborn
First steps of a D-Bus interface to the server.
320
    
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
321
    def __del__(self):
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
322
        self.disable_hook = None
323
        self.disable()
237.1.1 by Teddy Hogeborn
First steps of a D-Bus interface to the server.
324
    
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
325
    def checker_callback(self, pid, condition, command):
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
326
        """The checker has completed, so take appropriate actions."""
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
327
        self.checker_callback_tag = None
328
        self.checker = None
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
329
        if self.use_dbus:
330
            # Emit D-Bus signal
331
            self.PropertyChanged(dbus.String(u"checker_running"),
332
                                 dbus.Boolean(False, variant_level=1))
280 by Teddy Hogeborn
* mandos (Client.CheckerCompleted): Changed signature to "nxs"; return
333
        if os.WIFEXITED(condition):
334
            exitstatus = os.WEXITSTATUS(condition)
335
            if exitstatus == 0:
336
                logger.info(u"Checker for %(name)s succeeded",
337
                            vars(self))
281 by Teddy Hogeborn
* mandos (Client.bump_timeout): Renamed to "checked_ok". All callers
338
                self.checked_ok()
280 by Teddy Hogeborn
* mandos (Client.CheckerCompleted): Changed signature to "nxs"; return
339
            else:
340
                logger.info(u"Checker for %(name)s failed",
341
                            vars(self))
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
342
            if self.use_dbus:
343
                # Emit D-Bus signal
280 by Teddy Hogeborn
* mandos (Client.CheckerCompleted): Changed signature to "nxs"; return
344
                self.CheckerCompleted(dbus.Int16(exitstatus),
345
                                      dbus.Int64(condition),
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
346
                                      dbus.String(command))
280 by Teddy Hogeborn
* mandos (Client.CheckerCompleted): Changed signature to "nxs"; return
347
        else:
13 by Björn Påhlsson
Added following support:
348
            logger.warning(u"Checker for %(name)s crashed?",
349
                           vars(self))
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
350
            if self.use_dbus:
351
                # Emit D-Bus signal
280 by Teddy Hogeborn
* mandos (Client.CheckerCompleted): Changed signature to "nxs"; return
352
                self.CheckerCompleted(dbus.Int16(-1),
353
                                      dbus.Int64(condition),
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
354
                                      dbus.String(command))
237.1.1 by Teddy Hogeborn
First steps of a D-Bus interface to the server.
355
    
281 by Teddy Hogeborn
* mandos (Client.bump_timeout): Renamed to "checked_ok". All callers
356
    def checked_ok(self):
237 by Teddy Hogeborn
* mandos: Also import "with_statement" and "absolute_import" from
357
        """Bump up the timeout for this client.
358
        This should only be called when the client has been seen,
359
        alive and well.
360
        """
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
361
        self.last_checked_ok = datetime.datetime.utcnow()
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
362
        gobject.source_remove(self.disable_initiator_tag)
363
        self.disable_initiator_tag = (gobject.timeout_add
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
364
                                      (self.timeout_milliseconds(),
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
365
                                       self.disable))
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
366
        if self.use_dbus:
367
            # Emit D-Bus signal
368
            self.PropertyChanged(
369
                dbus.String(u"last_checked_ok"),
370
                (_datetime_to_dbus(self.last_checked_ok,
371
                                   variant_level=1)))
237.1.1 by Teddy Hogeborn
First steps of a D-Bus interface to the server.
372
    
9 by Teddy Hogeborn
* client.cpp (main): Get t_old early since it is used on error exits.
373
    def start_checker(self):
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
374
        """Start a new checker subprocess if one is not running.
375
        If a checker already exists, leave it running and do
376
        nothing."""
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
377
        # The reason for not killing a running checker is that if we
378
        # did that, then if a checker (for some reason) started
379
        # running slowly and taking more than 'interval' time, the
380
        # client would inevitably timeout, since no checker would get
381
        # a chance to run to completion.  If we instead leave running
382
        # checkers alone, the checker would have to take more time
383
        # than 'timeout' for the client to be declared invalid, which
384
        # is as it should be.
315 by Teddy Hogeborn
* mandos (Client.current_checker_command): New attribute.
385
        
386
        # If a checker exists, make sure it is not a zombie
387
        if self.checker is not None:
388
            pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
389
            if pid:
390
                logger.warning("Checker was a zombie")
391
                gobject.source_remove(self.checker_callback_tag)
392
                self.checker_callback(pid, status,
393
                                      self.current_checker_command)
394
        # Start a new checker if needed
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
395
        if self.checker is None:
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
396
            try:
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
397
                # In case checker_command has exactly one % operator
398
                command = self.checker_command % self.host
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
399
            except TypeError:
28 by Teddy Hogeborn
* server.conf: New file.
400
                # Escape attributes for the shell
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
401
                escaped_attrs = dict((key, re.escape(str(val)))
402
                                     for key, val in
403
                                     vars(self).iteritems())
13 by Björn Påhlsson
Added following support:
404
                try:
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
405
                    command = self.checker_command % escaped_attrs
13 by Björn Påhlsson
Added following support:
406
                except TypeError, error:
28 by Teddy Hogeborn
* server.conf: New file.
407
                    logger.error(u'Could not format string "%s":'
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
408
                                 u' %s', self.checker_command, error)
13 by Björn Påhlsson
Added following support:
409
                    return True # Try again later
315 by Teddy Hogeborn
* mandos (Client.current_checker_command): New attribute.
410
                self.current_checker_command = command
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
411
            try:
44 by Teddy Hogeborn
* ca.pem: Removed.
412
                logger.info(u"Starting checker %r for %s",
413
                            command, self.name)
94 by Teddy Hogeborn
* clients.conf ([DEFAULT]/checker): Update to new default value.
414
                # We don't need to redirect stdout and stderr, since
415
                # in normal mode, that is already done by daemon(),
416
                # and in debug mode we don't want to.  (Stdin is
417
                # always replaced by /dev/null.)
28 by Teddy Hogeborn
* server.conf: New file.
418
                self.checker = subprocess.Popen(command,
419
                                                close_fds=True,
420
                                                shell=True, cwd="/")
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
421
                if self.use_dbus:
422
                    # Emit D-Bus signal
423
                    self.CheckerStarted(command)
424
                    self.PropertyChanged(
425
                        dbus.String("checker_running"),
426
                        dbus.Boolean(True, variant_level=1))
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
427
                self.checker_callback_tag = (gobject.child_watch_add
428
                                             (self.checker.pid,
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
429
                                              self.checker_callback,
430
                                              data=command))
310 by Teddy Hogeborn
* mandos (Client.start_checker): Bug fix: Add extra check in case the
431
                # The checker may have completed before the gobject
432
                # watch was added.  Check for this.
433
                pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
434
                if pid:
435
                    gobject.source_remove(self.checker_callback_tag)
436
                    self.checker_callback(pid, status, command)
94 by Teddy Hogeborn
* clients.conf ([DEFAULT]/checker): Update to new default value.
437
            except OSError, error:
13 by Björn Påhlsson
Added following support:
438
                logger.error(u"Failed to start subprocess: %s",
439
                             error)
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
440
        # Re-run this periodically if run by gobject.timeout_add
441
        return True
237.1.1 by Teddy Hogeborn
First steps of a D-Bus interface to the server.
442
    
9 by Teddy Hogeborn
* client.cpp (main): Get t_old early since it is used on error exits.
443
    def stop_checker(self):
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
444
        """Force the checker process, if any, to stop."""
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
445
        if self.checker_callback_tag:
446
            gobject.source_remove(self.checker_callback_tag)
447
            self.checker_callback_tag = None
28 by Teddy Hogeborn
* server.conf: New file.
448
        if getattr(self, "checker", None) is None:
9 by Teddy Hogeborn
* client.cpp (main): Get t_old early since it is used on error exits.
449
            return
51 by Teddy Hogeborn
* clients.conf: Better comments.
450
        logger.debug(u"Stopping checker for %(name)s", vars(self))
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
451
        try:
452
            os.kill(self.checker.pid, signal.SIGTERM)
453
            #os.sleep(0.5)
454
            #if self.checker.poll() is None:
455
            #    os.kill(self.checker.pid, signal.SIGKILL)
456
        except OSError, error:
28 by Teddy Hogeborn
* server.conf: New file.
457
            if error.errno != errno.ESRCH: # No such process
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
458
                raise
9 by Teddy Hogeborn
* client.cpp (main): Get t_old early since it is used on error exits.
459
        self.checker = None
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
460
        if self.use_dbus:
461
            self.PropertyChanged(dbus.String(u"checker_running"),
462
                                 dbus.Boolean(False, variant_level=1))
237.1.1 by Teddy Hogeborn
First steps of a D-Bus interface to the server.
463
    
28 by Teddy Hogeborn
* server.conf: New file.
464
    def still_valid(self):
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
465
        """Has the timeout not yet passed for this client?"""
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
466
        if not getattr(self, "enabled", False):
237.1.1 by Teddy Hogeborn
First steps of a D-Bus interface to the server.
467
            return False
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
468
        now = datetime.datetime.utcnow()
28 by Teddy Hogeborn
* server.conf: New file.
469
        if self.last_checked_ok is None:
10 by Teddy Hogeborn
* server.py: Bug fix: Do "from __future__ import division".
470
            return now < (self.created + self.timeout)
471
        else:
28 by Teddy Hogeborn
* server.conf: New file.
472
            return now < (self.last_checked_ok + self.timeout)
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
473
    
474
    ## D-Bus methods & signals
279 by Teddy Hogeborn
* mandos (Client.__init__): Disable D-Bus during init to avoid
475
    _interface = u"se.bsnet.fukt.Mandos.Client"
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
476
    
281 by Teddy Hogeborn
* mandos (Client.bump_timeout): Renamed to "checked_ok". All callers
477
    # CheckedOK - method
478
    CheckedOK = dbus.service.method(_interface)(checked_ok)
479
    CheckedOK.__name__ = "CheckedOK"
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
480
    
481
    # CheckerCompleted - signal
280 by Teddy Hogeborn
* mandos (Client.CheckerCompleted): Changed signature to "nxs"; return
482
    @dbus.service.signal(_interface, signature="nxs")
483
    def CheckerCompleted(self, exitcode, waitstatus, command):
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
484
        "D-Bus signal"
485
        pass
486
    
487
    # CheckerStarted - signal
488
    @dbus.service.signal(_interface, signature="s")
489
    def CheckerStarted(self, command):
490
        "D-Bus signal"
491
        pass
492
    
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
493
    # GetAllProperties - method
494
    @dbus.service.method(_interface, out_signature="a{sv}")
495
    def GetAllProperties(self):
496
        "D-Bus method"
497
        return dbus.Dictionary({
498
                dbus.String("name"):
499
                    dbus.String(self.name, variant_level=1),
500
                dbus.String("fingerprint"):
501
                    dbus.String(self.fingerprint, variant_level=1),
502
                dbus.String("host"):
503
                    dbus.String(self.host, variant_level=1),
504
                dbus.String("created"):
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
505
                    _datetime_to_dbus(self.created, variant_level=1),
506
                dbus.String("last_enabled"):
507
                    (_datetime_to_dbus(self.last_enabled,
508
                                       variant_level=1)
509
                     if self.last_enabled is not None
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
510
                     else dbus.Boolean(False, variant_level=1)),
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
511
                dbus.String("enabled"):
512
                    dbus.Boolean(self.enabled, variant_level=1),
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
513
                dbus.String("last_checked_ok"):
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
514
                    (_datetime_to_dbus(self.last_checked_ok,
515
                                       variant_level=1)
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
516
                     if self.last_checked_ok is not None
517
                     else dbus.Boolean (False, variant_level=1)),
518
                dbus.String("timeout"):
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
519
                    dbus.UInt64(self.timeout_milliseconds(),
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
520
                                variant_level=1),
521
                dbus.String("interval"):
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
522
                    dbus.UInt64(self.interval_milliseconds(),
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
523
                                variant_level=1),
524
                dbus.String("checker"):
525
                    dbus.String(self.checker_command,
526
                                variant_level=1),
527
                dbus.String("checker_running"):
528
                    dbus.Boolean(self.checker is not None,
529
                                 variant_level=1),
278 by Teddy Hogeborn
* mandos (Client.GetAllProperties): Also send Client.dbus_object_path
530
                dbus.String("object_path"):
531
                    dbus.ObjectPath(self.dbus_object_path,
532
                                    variant_level=1)
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
533
                }, signature="sv")
534
    
535
    # IsStillValid - method
536
    IsStillValid = (dbus.service.method(_interface, out_signature="b")
537
                    (still_valid))
538
    IsStillValid.__name__ = "IsStillValid"
539
    
540
    # PropertyChanged - signal
541
    @dbus.service.signal(_interface, signature="sv")
542
    def PropertyChanged(self, property, value):
543
        "D-Bus signal"
544
        pass
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
545
    
327 by Teddy Hogeborn
Merge from pipe IPC branch.
546
    # ReceivedSecret - signal
547
    @dbus.service.signal(_interface)
548
    def ReceivedSecret(self):
549
        "D-Bus signal"
550
        pass
551
    
552
    # Rejected - signal
553
    @dbus.service.signal(_interface)
554
    def Rejected(self):
555
        "D-Bus signal"
556
        pass
557
    
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
558
    # SetChecker - method
559
    @dbus.service.method(_interface, in_signature="s")
560
    def SetChecker(self, checker):
561
        "D-Bus setter method"
562
        self.checker_command = checker
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
563
        # Emit D-Bus signal
564
        self.PropertyChanged(dbus.String(u"checker"),
565
                             dbus.String(self.checker_command,
566
                                         variant_level=1))
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
567
    
568
    # SetHost - method
569
    @dbus.service.method(_interface, in_signature="s")
570
    def SetHost(self, host):
571
        "D-Bus setter method"
572
        self.host = host
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
573
        # Emit D-Bus signal
574
        self.PropertyChanged(dbus.String(u"host"),
575
                             dbus.String(self.host, variant_level=1))
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
576
    
577
    # SetInterval - method
578
    @dbus.service.method(_interface, in_signature="t")
579
    def SetInterval(self, milliseconds):
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
580
        self.interval = datetime.timedelta(0, 0, 0, milliseconds)
581
        # Emit D-Bus signal
582
        self.PropertyChanged(dbus.String(u"interval"),
583
                             (dbus.UInt64(self.interval_milliseconds(),
584
                                          variant_level=1)))
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
585
    
586
    # SetSecret - method
587
    @dbus.service.method(_interface, in_signature="ay",
588
                         byte_arrays=True)
589
    def SetSecret(self, secret):
590
        "D-Bus setter method"
591
        self.secret = str(secret)
592
    
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
593
    # SetTimeout - method
594
    @dbus.service.method(_interface, in_signature="t")
595
    def SetTimeout(self, milliseconds):
596
        self.timeout = datetime.timedelta(0, 0, 0, milliseconds)
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
597
        # Emit D-Bus signal
598
        self.PropertyChanged(dbus.String(u"timeout"),
599
                             (dbus.UInt64(self.timeout_milliseconds(),
600
                                          variant_level=1)))
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
601
    
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
602
    # Enable - method
603
    Enable = dbus.service.method(_interface)(enable)
604
    Enable.__name__ = "Enable"
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
605
    
606
    # StartChecker - method
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
607
    @dbus.service.method(_interface)
608
    def StartChecker(self):
609
        "D-Bus method"
610
        self.start_checker()
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
611
    
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
612
    # Disable - method
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
613
    @dbus.service.method(_interface)
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
614
    def Disable(self):
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
615
        "D-Bus method"
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
616
        self.disable()
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
617
    
618
    # StopChecker - method
619
    StopChecker = dbus.service.method(_interface)(stop_checker)
620
    StopChecker.__name__ = "StopChecker"
621
    
622
    del _interface
3 by Björn Påhlsson
Python based server
623
624
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
625
def peer_certificate(session):
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
626
    "Return the peer's OpenPGP certificate as a bytestring"
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
627
    # If not an OpenPGP certificate...
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
628
    if (gnutls.library.functions
629
        .gnutls_certificate_type_get(session._c_object)
630
        != gnutls.library.constants.GNUTLS_CRT_OPENPGP):
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
631
        # ...do the normal thing
632
        return session.peer_certificate
283 by Teddy Hogeborn
* mandos (peer_certificate): Handle NULL pointer from
633
    list_size = ctypes.c_uint(1)
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
634
    cert_list = (gnutls.library.functions
635
                 .gnutls_certificate_get_peers
636
                 (session._c_object, ctypes.byref(list_size)))
283 by Teddy Hogeborn
* mandos (peer_certificate): Handle NULL pointer from
637
    if not bool(cert_list) and list_size.value != 0:
638
        raise gnutls.errors.GNUTLSError("error getting peer"
639
                                        " certificate")
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
640
    if list_size.value == 0:
641
        return None
642
    cert = cert_list[0]
643
    return ctypes.string_at(cert.data, cert.size)
644
645
646
def fingerprint(openpgp):
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
647
    "Convert an OpenPGP bytestring to a hexdigit fingerprint string"
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
648
    # New GnuTLS "datum" with the OpenPGP public key
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
649
    datum = (gnutls.library.types
650
             .gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp),
651
                                         ctypes.POINTER
652
                                         (ctypes.c_ubyte)),
653
                             ctypes.c_uint(len(openpgp))))
45 by Teddy Hogeborn
* server.py: Cosmetic changes.
654
    # New empty GnuTLS certificate
655
    crt = gnutls.library.types.gnutls_openpgp_crt_t()
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
656
    (gnutls.library.functions
657
     .gnutls_openpgp_crt_init(ctypes.byref(crt)))
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
658
    # Import the OpenPGP public key into the certificate
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
659
    (gnutls.library.functions
660
     .gnutls_openpgp_crt_import(crt, ctypes.byref(datum),
661
                                gnutls.library.constants
662
                                .GNUTLS_OPENPGP_FMT_RAW))
24.1.62 by Björn Påhlsson
merge + small bugfix
663
    # Verify the self signature in the key
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
664
    crtverify = ctypes.c_uint()
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
665
    (gnutls.library.functions
666
     .gnutls_openpgp_crt_verify_self(crt, 0, ctypes.byref(crtverify)))
99 by Teddy Hogeborn
* mandos (fingerprint): Bug fix: Check crtverify.value, not crtverify.
667
    if crtverify.value != 0:
24.1.62 by Björn Påhlsson
merge + small bugfix
668
        gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
669
        raise gnutls.errors.CertificateSecurityError("Verify failed")
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
670
    # New buffer for the fingerprint
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
671
    buf = ctypes.create_string_buffer(20)
672
    buf_len = ctypes.c_size_t()
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
673
    # Get the fingerprint from the certificate into the buffer
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
674
    (gnutls.library.functions
675
     .gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
676
                                         ctypes.byref(buf_len)))
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
677
    # Deinit the certificate
678
    gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
679
    # Convert the buffer to a Python bytestring
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
680
    fpr = ctypes.string_at(buf, buf_len.value)
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
681
    # Convert the bytestring to hexadecimal notation
682
    hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
683
    return hex_fpr
684
685
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
686
class TCP_handler(SocketServer.BaseRequestHandler, object):
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
687
    """A TCP request handler class.
688
    Instantiated by IPv6_TCPServer for each request to handle it.
689
    Note: This will run in its own forked process."""
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
690
    
3 by Björn Påhlsson
Python based server
691
    def handle(self):
44 by Teddy Hogeborn
* ca.pem: Removed.
692
        logger.info(u"TCP connection from: %s",
237 by Teddy Hogeborn
* mandos: Also import "with_statement" and "absolute_import" from
693
                    unicode(self.client_address))
327 by Teddy Hogeborn
Merge from pipe IPC branch.
694
        logger.debug(u"IPC Pipe FD: %d", self.server.pipe[1])
288.1.1 by Teddy Hogeborn
Start of new pipe-based IPC mechanism.
695
        # Open IPC pipe to parent process
696
        with closing(os.fdopen(self.server.pipe[1], "w", 1)) as ipc:
697
            session = (gnutls.connection
698
                       .ClientSession(self.request,
699
                                      gnutls.connection
700
                                      .X509Credentials()))
701
            
702
            line = self.request.makefile().readline()
703
            logger.debug(u"Protocol version: %r", line)
704
            try:
705
                if int(line.strip().split()[0]) > 1:
706
                    raise RuntimeError
707
            except (ValueError, IndexError, RuntimeError), error:
708
                logger.error(u"Unknown protocol version: %s", error)
709
                return
710
            
711
            # Note: gnutls.connection.X509Credentials is really a
712
            # generic GnuTLS certificate credentials object so long as
713
            # no X.509 keys are added to it.  Therefore, we can use it
714
            # here despite using OpenPGP certificates.
715
            
716
            #priority = ':'.join(("NONE", "+VERS-TLS1.1",
717
            #                     "+AES-256-CBC", "+SHA1",
718
            #                     "+COMP-NULL", "+CTYPE-OPENPGP",
719
            #                     "+DHE-DSS"))
720
            # Use a fallback default, since this MUST be set.
721
            priority = self.server.settings.get("priority", "NORMAL")
722
            (gnutls.library.functions
723
             .gnutls_priority_set_direct(session._c_object,
724
                                         priority, None))
288.1.2 by Teddy Hogeborn
Merge from trunk.
725
            
288.1.1 by Teddy Hogeborn
Start of new pipe-based IPC mechanism.
726
            try:
727
                session.handshake()
728
            except gnutls.errors.GNUTLSError, error:
729
                logger.warning(u"Handshake failed: %s", error)
730
                # Do not run session.bye() here: the session is not
731
                # established.  Just abandon the request.
732
                return
733
            logger.debug(u"Handshake succeeded")
734
            try:
735
                fpr = fingerprint(peer_certificate(session))
736
            except (TypeError, gnutls.errors.GNUTLSError), error:
737
                logger.warning(u"Bad certificate: %s", error)
738
                session.bye()
739
                return
740
            logger.debug(u"Fingerprint: %s", fpr)
288.1.2 by Teddy Hogeborn
Merge from trunk.
741
            
288.1.1 by Teddy Hogeborn
Start of new pipe-based IPC mechanism.
742
            for c in self.server.clients:
743
                if c.fingerprint == fpr:
744
                    client = c
745
                    break
746
            else:
747
                logger.warning(u"Client not found for fingerprint: %s",
748
                               fpr)
749
                ipc.write("NOTFOUND %s\n" % fpr)
750
                session.bye()
751
                return
752
            # Have to check if client.still_valid(), since it is
753
            # possible that the client timed out while establishing
754
            # the GnuTLS session.
755
            if not client.still_valid():
756
                logger.warning(u"Client %(name)s is invalid",
757
                               vars(client))
758
                ipc.write("INVALID %s\n" % client.name)
759
                session.bye()
760
                return
761
            ipc.write("SENDING %s\n" % client.name)
762
            sent_size = 0
763
            while sent_size < len(client.secret):
764
                sent = session.send(client.secret[sent_size:])
765
                logger.debug(u"Sent: %d, remaining: %d",
766
                             sent, len(client.secret)
767
                             - (sent_size + sent))
768
                sent_size += sent
769
            session.bye()
770
771
772
class ForkingMixInWithPipe(SocketServer.ForkingMixIn, object):
773
    """Like SocketServer.ForkingMixIn, but also pass a pipe.
774
    Assumes a gobject.MainLoop event loop.
775
    """
776
    def process_request(self, request, client_address):
777
        """This overrides and wraps the original process_request().
778
        This function creates a new pipe in self.pipe 
779
        """
780
        self.pipe = os.pipe()
781
        super(ForkingMixInWithPipe,
782
              self).process_request(request, client_address)
783
        os.close(self.pipe[1])  # close write end
784
        # Call "handle_ipc" for both data and EOF events
785
        gobject.io_add_watch(self.pipe[0],
786
                             gobject.IO_IN | gobject.IO_HUP,
787
                             self.handle_ipc)
788
    def handle_ipc(source, condition):
789
        """Dummy function; override as necessary"""
790
        os.close(source)
791
        return False
792
793
794
class IPv6_TCPServer(ForkingMixInWithPipe,
237 by Teddy Hogeborn
* mandos: Also import "with_statement" and "absolute_import" from
795
                     SocketServer.TCPServer, object):
237.2.13 by Teddy Hogeborn
Merge from trunk. Notable changes:
796
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
797
    Attributes:
28 by Teddy Hogeborn
* server.conf: New file.
798
        settings:       Server settings
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
799
        clients:        Set() of Client objects
163 by Teddy Hogeborn
* Makefile (PIDDIR, USER, GROUP): Removed.
800
        enabled:        Boolean; whether this server is activated yet
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
801
    """
802
    address_family = socket.AF_INET6
803
    def __init__(self, *args, **kwargs):
28 by Teddy Hogeborn
* server.conf: New file.
804
        if "settings" in kwargs:
805
            self.settings = kwargs["settings"]
806
            del kwargs["settings"]
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
807
        if "clients" in kwargs:
808
            self.clients = kwargs["clients"]
809
            del kwargs["clients"]
314 by Teddy Hogeborn
Support not using IPv6 in server:
810
        if "use_ipv6" in kwargs:
811
            if not kwargs["use_ipv6"]:
812
                self.address_family = socket.AF_INET
813
            del kwargs["use_ipv6"]
163 by Teddy Hogeborn
* Makefile (PIDDIR, USER, GROUP): Removed.
814
        self.enabled = False
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
815
        super(IPv6_TCPServer, self).__init__(*args, **kwargs)
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
816
    def server_bind(self):
817
        """This overrides the normal server_bind() function
818
        to bind to an interface if one was specified, and also NOT to
819
        bind to an address or port if they were not specified."""
29 by Teddy Hogeborn
* plugins.d/mandosclient.c (start_mandos_communication): Changed
820
        if self.settings["interface"]:
28 by Teddy Hogeborn
* server.conf: New file.
821
            # 25 is from /usr/include/asm-i486/socket.h
822
            SO_BINDTODEVICE = getattr(socket, "SO_BINDTODEVICE", 25)
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
823
            try:
824
                self.socket.setsockopt(socket.SOL_SOCKET,
28 by Teddy Hogeborn
* server.conf: New file.
825
                                       SO_BINDTODEVICE,
826
                                       self.settings["interface"])
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
827
            except socket.error, error:
828
                if error[0] == errno.EPERM:
44 by Teddy Hogeborn
* ca.pem: Removed.
829
                    logger.error(u"No permission to"
830
                                 u" bind to interface %s",
831
                                 self.settings["interface"])
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
832
                else:
292 by Teddy Hogeborn
* Makefile (run-server): Use "--no-dbus" unconditionally.
833
                    raise
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
834
        # Only bind(2) the socket if we really need to.
835
        if self.server_address[0] or self.server_address[1]:
836
            if not self.server_address[0]:
314 by Teddy Hogeborn
Support not using IPv6 in server:
837
                if self.address_family == socket.AF_INET6:
838
                    any_address = "::" # in6addr_any
839
                else:
840
                    any_address = socket.INADDR_ANY
841
                self.server_address = (any_address,
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
842
                                       self.server_address[1])
49 by Teddy Hogeborn
* mandos (IPv6_TCPServer.server_bind): Bug fix: allow port to be empty
843
            elif not self.server_address[1]:
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
844
                self.server_address = (self.server_address[0],
845
                                       0)
49 by Teddy Hogeborn
* mandos (IPv6_TCPServer.server_bind): Bug fix: allow port to be empty
846
#                 if self.settings["interface"]:
847
#                     self.server_address = (self.server_address[0],
848
#                                            0, # port
849
#                                            0, # flowinfo
850
#                                            if_nametoindex
851
#                                            (self.settings
852
#                                             ["interface"]))
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
853
            return super(IPv6_TCPServer, self).server_bind()
163 by Teddy Hogeborn
* Makefile (PIDDIR, USER, GROUP): Removed.
854
    def server_activate(self):
855
        if self.enabled:
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
856
            return super(IPv6_TCPServer, self).server_activate()
163 by Teddy Hogeborn
* Makefile (PIDDIR, USER, GROUP): Removed.
857
    def enable(self):
858
        self.enabled = True
288.1.1 by Teddy Hogeborn
Start of new pipe-based IPC mechanism.
859
    def handle_ipc(self, source, condition, file_objects={}):
327 by Teddy Hogeborn
Merge from pipe IPC branch.
860
        condition_names = {
861
            gobject.IO_IN: "IN", # There is data to read.
862
            gobject.IO_OUT: "OUT", # Data can be written (without
863
                                   # blocking).
864
            gobject.IO_PRI: "PRI", # There is urgent data to read.
865
            gobject.IO_ERR: "ERR", # Error condition.
866
            gobject.IO_HUP: "HUP"  # Hung up (the connection has been
867
                                   # broken, usually for pipes and
868
                                   # sockets).
869
            }
870
        conditions_string = ' | '.join(name
871
                                       for cond, name in
872
                                       condition_names.iteritems()
873
                                       if cond & condition)
874
        logger.debug("Handling IPC: FD = %d, condition = %s", source,
875
                     conditions_string)
288.1.1 by Teddy Hogeborn
Start of new pipe-based IPC mechanism.
876
        
327 by Teddy Hogeborn
Merge from pipe IPC branch.
877
        # Turn the pipe file descriptor into a Python file object
288.1.1 by Teddy Hogeborn
Start of new pipe-based IPC mechanism.
878
        if source not in file_objects:
879
            file_objects[source] = os.fdopen(source, "r", 1)
880
        
881
        # Read a line from the file object
882
        cmdline = file_objects[source].readline()
883
        if not cmdline:             # Empty line means end of file
884
            # close the IPC pipe
885
            file_objects[source].close()
886
            del file_objects[source]
327 by Teddy Hogeborn
Merge from pipe IPC branch.
887
            
288.1.1 by Teddy Hogeborn
Start of new pipe-based IPC mechanism.
888
            # Stop calling this function
889
            return False
890
        
891
        logger.debug("IPC command: %r\n" % cmdline)
892
        
893
        # Parse and act on command
894
        cmd, args = cmdline.split(None, 1)
895
        if cmd == "NOTFOUND":
327 by Teddy Hogeborn
Merge from pipe IPC branch.
896
            if self.settings["use_dbus"]:
897
                # Emit D-Bus signal
898
                mandos_dbus_service.ClientNotFound(args)
288.1.1 by Teddy Hogeborn
Start of new pipe-based IPC mechanism.
899
        elif cmd == "INVALID":
327 by Teddy Hogeborn
Merge from pipe IPC branch.
900
            if self.settings["use_dbus"]:
901
                for client in self.clients:
902
                    if client.name == args:
903
                        # Emit D-Bus signal
904
                        client.Rejected()
905
                        break
288.1.1 by Teddy Hogeborn
Start of new pipe-based IPC mechanism.
906
        elif cmd == "SENDING":
327 by Teddy Hogeborn
Merge from pipe IPC branch.
907
            for client in self.clients:
908
                if client.name == args:
909
                    client.checked_ok()
910
                    if self.settings["use_dbus"]:
911
                        # Emit D-Bus signal
912
                        client.ReceivedSecret()
913
                    break
288.1.1 by Teddy Hogeborn
Start of new pipe-based IPC mechanism.
914
        else:
915
            logger.error("Unknown IPC command: %r", cmdline)
916
        
917
        # Keep calling this function
918
        return True
10 by Teddy Hogeborn
* server.py: Bug fix: Do "from __future__ import division".
919
3 by Björn Påhlsson
Python based server
920
4 by Teddy Hogeborn
* server.py (Client.created, Client.next_check): New.
921
def string_to_delta(interval):
922
    """Parse a string and return a datetime.timedelta
290 by Teddy Hogeborn
* mandos (main): Bug fix: Do setgid before setuid. Add verbose GnuTLS
923
    
4 by Teddy Hogeborn
* server.py (Client.created, Client.next_check): New.
924
    >>> string_to_delta('7d')
925
    datetime.timedelta(7)
926
    >>> string_to_delta('60s')
927
    datetime.timedelta(0, 60)
928
    >>> string_to_delta('60m')
929
    datetime.timedelta(0, 3600)
930
    >>> string_to_delta('24h')
931
    datetime.timedelta(1)
932
    >>> string_to_delta(u'1w')
933
    datetime.timedelta(7)
93 by Teddy Hogeborn
* mandos (string_to_delta): Accept a whitespace-separated sequence of
934
    >>> string_to_delta('5m 30s')
935
    datetime.timedelta(0, 330)
4 by Teddy Hogeborn
* server.py (Client.created, Client.next_check): New.
936
    """
93 by Teddy Hogeborn
* mandos (string_to_delta): Accept a whitespace-separated sequence of
937
    timevalue = datetime.timedelta(0)
938
    for s in interval.split():
939
        try:
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
940
            suffix = unicode(s[-1])
941
            value = int(s[:-1])
93 by Teddy Hogeborn
* mandos (string_to_delta): Accept a whitespace-separated sequence of
942
            if suffix == u"d":
943
                delta = datetime.timedelta(value)
944
            elif suffix == u"s":
945
                delta = datetime.timedelta(0, value)
946
            elif suffix == u"m":
947
                delta = datetime.timedelta(0, 0, 0, 0, value)
948
            elif suffix == u"h":
949
                delta = datetime.timedelta(0, 0, 0, 0, 0, value)
950
            elif suffix == u"w":
951
                delta = datetime.timedelta(0, 0, 0, 0, 0, 0, value)
952
            else:
953
                raise ValueError
954
        except (ValueError, IndexError):
4 by Teddy Hogeborn
* server.py (Client.created, Client.next_check): New.
955
            raise ValueError
93 by Teddy Hogeborn
* mandos (string_to_delta): Accept a whitespace-separated sequence of
956
        timevalue += delta
957
    return timevalue
4 by Teddy Hogeborn
* server.py (Client.created, Client.next_check): New.
958
8 by Teddy Hogeborn
* Makefile (client_debug): Bug fix; add quotes and / to CERT_ROOT.
959
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
960
def server_state_changed(state):
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
961
    """Derived from the Avahi example code"""
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
962
    if state == avahi.SERVER_COLLISION:
109 by Teddy Hogeborn
* .bzrignore: New.
963
        logger.error(u"Zeroconf server name collision")
28 by Teddy Hogeborn
* server.conf: New file.
964
        service.remove()
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
965
    elif state == avahi.SERVER_RUNNING:
28 by Teddy Hogeborn
* server.conf: New file.
966
        service.add()
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
967
968
969
def entry_group_state_changed(state, error):
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
970
    """Derived from the Avahi example code"""
109 by Teddy Hogeborn
* .bzrignore: New.
971
    logger.debug(u"Avahi state change: %i", state)
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
972
    
973
    if state == avahi.ENTRY_GROUP_ESTABLISHED:
109 by Teddy Hogeborn
* .bzrignore: New.
974
        logger.debug(u"Zeroconf service established.")
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
975
    elif state == avahi.ENTRY_GROUP_COLLISION:
109 by Teddy Hogeborn
* .bzrignore: New.
976
        logger.warning(u"Zeroconf service name collision.")
28 by Teddy Hogeborn
* server.conf: New file.
977
        service.rename()
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
978
    elif state == avahi.ENTRY_GROUP_FAILURE:
109 by Teddy Hogeborn
* .bzrignore: New.
979
        logger.critical(u"Avahi: Error in group state changed %s",
28 by Teddy Hogeborn
* server.conf: New file.
980
                        unicode(error))
242 by Teddy Hogeborn
* mandos (AvahiError): Converted to use unicode. All users changed.
981
        raise AvahiGroupError(u"State changed: %s" % unicode(error))
28 by Teddy Hogeborn
* server.conf: New file.
982
24.1.13 by Björn Påhlsson
mandosclient
983
def if_nametoindex(interface):
28 by Teddy Hogeborn
* server.conf: New file.
984
    """Call the C function if_nametoindex(), or equivalent"""
24.1.13 by Björn Påhlsson
mandosclient
985
    global if_nametoindex
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
986
    try:
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
987
        if_nametoindex = (ctypes.cdll.LoadLibrary
988
                          (ctypes.util.find_library("c"))
989
                          .if_nametoindex)
12 by Teddy Hogeborn
* mandos-clients.conf ([foo]/dn, [foo]/password, [braxen_client]/dn,
990
    except (OSError, AttributeError):
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
991
        if "struct" not in sys.modules:
992
            import struct
993
        if "fcntl" not in sys.modules:
994
            import fcntl
24.1.13 by Björn Påhlsson
mandosclient
995
        def if_nametoindex(interface):
28 by Teddy Hogeborn
* server.conf: New file.
996
            "Get an interface index the hard way, i.e. using fcntl()"
997
            SIOCGIFINDEX = 0x8933  # From /usr/include/linux/sockios.h
237 by Teddy Hogeborn
* mandos: Also import "with_statement" and "absolute_import" from
998
            with closing(socket.socket()) as s:
999
                ifreq = fcntl.ioctl(s, SIOCGIFINDEX,
1000
                                    struct.pack("16s16x", interface))
28 by Teddy Hogeborn
* server.conf: New file.
1001
            interface_index = struct.unpack("I", ifreq[16:20])[0]
1002
            return interface_index
24.1.13 by Björn Påhlsson
mandosclient
1003
    return if_nametoindex(interface)
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
1004
1005
47 by Teddy Hogeborn
* plugbasedclient.c: Renamed to "mandos-client.c". All users changed.
1006
def daemon(nochdir = False, noclose = False):
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
1007
    """See daemon(3).  Standard BSD Unix function.
1008
    This should really exist as os.daemon, but it doesn't (yet)."""
1009
    if os.fork():
1010
        sys.exit()
1011
    os.setsid()
1012
    if not nochdir:
1013
        os.chdir("/")
46 by Teddy Hogeborn
* network-protocol.txt: New.
1014
    if os.fork():
1015
        sys.exit()
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
1016
    if not noclose:
1017
        # Close all standard open file descriptors
28 by Teddy Hogeborn
* server.conf: New file.
1018
        null = os.open(os.path.devnull, os.O_NOCTTY | os.O_RDWR)
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
1019
        if not stat.S_ISCHR(os.fstat(null).st_mode):
1020
            raise OSError(errno.ENODEV,
1021
                          "/dev/null not a character device")
1022
        os.dup2(null, sys.stdin.fileno())
1023
        os.dup2(null, sys.stdout.fileno())
1024
        os.dup2(null, sys.stderr.fileno())
1025
        if null > 2:
1026
            os.close(null)
1027
1028
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
1029
def main():
327 by Teddy Hogeborn
Merge from pipe IPC branch.
1030
    
1031
    ######################################################################
1032
    # Parsing of options, both command line and config file
1033
    
237.2.1 by Teddy Hogeborn
Merge from trunk, but disable the unfinished D-Bus feature:
1034
    parser = optparse.OptionParser(version = "%%prog %s" % version)
3 by Björn Påhlsson
Python based server
1035
    parser.add_option("-i", "--interface", type="string",
28 by Teddy Hogeborn
* server.conf: New file.
1036
                      metavar="IF", help="Bind to interface IF")
1037
    parser.add_option("-a", "--address", type="string",
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
1038
                      help="Address to listen for requests on")
28 by Teddy Hogeborn
* server.conf: New file.
1039
    parser.add_option("-p", "--port", type="int",
3 by Björn Påhlsson
Python based server
1040
                      help="Port number to receive requests on")
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1041
    parser.add_option("--check", action="store_true",
4 by Teddy Hogeborn
* server.py (Client.created, Client.next_check): New.
1042
                      help="Run self-test")
49 by Teddy Hogeborn
* mandos (IPv6_TCPServer.server_bind): Bug fix: allow port to be empty
1043
    parser.add_option("--debug", action="store_true",
28 by Teddy Hogeborn
* server.conf: New file.
1044
                      help="Debug mode; run in foreground and log to"
1045
                      " terminal")
1046
    parser.add_option("--priority", type="string", help="GnuTLS"
1047
                      " priority string (see GnuTLS documentation)")
1048
    parser.add_option("--servicename", type="string", metavar="NAME",
1049
                      help="Zeroconf service name")
1050
    parser.add_option("--configdir", type="string",
1051
                      default="/etc/mandos", metavar="DIR",
1052
                      help="Directory to search for configuration"
1053
                      " files")
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1054
    parser.add_option("--no-dbus", action="store_false",
1055
                      dest="use_dbus",
324 by Teddy Hogeborn
Merge from release branch.
1056
                      help="Do not provide D-Bus system bus"
1057
                      " interface")
314 by Teddy Hogeborn
Support not using IPv6 in server:
1058
    parser.add_option("--no-ipv6", action="store_false",
1059
                      dest="use_ipv6", help="Do not use IPv6")
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
1060
    options = parser.parse_args()[0]
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
1061
    
4 by Teddy Hogeborn
* server.py (Client.created, Client.next_check): New.
1062
    if options.check:
1063
        import doctest
1064
        doctest.testmod()
1065
        sys.exit()
3 by Björn Påhlsson
Python based server
1066
    
28 by Teddy Hogeborn
* server.conf: New file.
1067
    # Default values for config file for server-global settings
1068
    server_defaults = { "interface": "",
1069
                        "address": "",
1070
                        "port": "",
1071
                        "debug": "False",
1072
                        "priority":
1073
                        "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
1074
                        "servicename": "Mandos",
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1075
                        "use_dbus": "True",
314 by Teddy Hogeborn
Support not using IPv6 in server:
1076
                        "use_ipv6": "True",
28 by Teddy Hogeborn
* server.conf: New file.
1077
                        }
1078
    
1079
    # Parse config file for server-global settings
1080
    server_config = ConfigParser.SafeConfigParser(server_defaults)
1081
    del server_defaults
47 by Teddy Hogeborn
* plugbasedclient.c: Renamed to "mandos-client.c". All users changed.
1082
    server_config.read(os.path.join(options.configdir, "mandos.conf"))
28 by Teddy Hogeborn
* server.conf: New file.
1083
    # Convert the SafeConfigParser object to a dict
89 by Teddy Hogeborn
* Makefile: Bug fix: fixed creation of man pages for section 5 pages.
1084
    server_settings = server_config.defaults()
282 by Teddy Hogeborn
* mandos (main): Bug fix: use "getint" on the "port" config file
1085
    # Use the appropriate methods on the non-string config options
1086
    server_settings["debug"] = server_config.getboolean("DEFAULT",
1087
                                                        "debug")
1088
    server_settings["use_dbus"] = server_config.getboolean("DEFAULT",
1089
                                                           "use_dbus")
314 by Teddy Hogeborn
Support not using IPv6 in server:
1090
    server_settings["use_ipv6"] = server_config.getboolean("DEFAULT",
1091
                                                           "use_ipv6")
282 by Teddy Hogeborn
* mandos (main): Bug fix: use "getint" on the "port" config file
1092
    if server_settings["port"]:
1093
        server_settings["port"] = server_config.getint("DEFAULT",
1094
                                                       "port")
28 by Teddy Hogeborn
* server.conf: New file.
1095
    del server_config
1096
    
1097
    # Override the settings from the config file with command line
1098
    # options, if set.
1099
    for option in ("interface", "address", "port", "debug",
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1100
                   "priority", "servicename", "configdir",
314 by Teddy Hogeborn
Support not using IPv6 in server:
1101
                   "use_dbus", "use_ipv6"):
28 by Teddy Hogeborn
* server.conf: New file.
1102
        value = getattr(options, option)
1103
        if value is not None:
1104
            server_settings[option] = value
1105
    del options
1106
    # Now we have our good server settings in "server_settings"
1107
    
327 by Teddy Hogeborn
Merge from pipe IPC branch.
1108
    ##################################################################
1109
    
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1110
    # For convenience
52 by Teddy Hogeborn
* mandos: Make syslog use "/dev/log" instead of UDP to localhost.
1111
    debug = server_settings["debug"]
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1112
    use_dbus = server_settings["use_dbus"]
314 by Teddy Hogeborn
Support not using IPv6 in server:
1113
    use_ipv6 = server_settings["use_ipv6"]
52 by Teddy Hogeborn
* mandos: Make syslog use "/dev/log" instead of UDP to localhost.
1114
    
1115
    if not debug:
1116
        syslogger.setLevel(logging.WARNING)
61 by Teddy Hogeborn
* mandos (console): Define handler globally.
1117
        console.setLevel(logging.WARNING)
52 by Teddy Hogeborn
* mandos: Make syslog use "/dev/log" instead of UDP to localhost.
1118
    
1119
    if server_settings["servicename"] != "Mandos":
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
1120
        syslogger.setFormatter(logging.Formatter
327 by Teddy Hogeborn
Merge from pipe IPC branch.
1121
                               ('Mandos (%s) [%%(process)d]:'
1122
                                ' %%(levelname)s: %%(message)s'
52 by Teddy Hogeborn
* mandos: Make syslog use "/dev/log" instead of UDP to localhost.
1123
                                % server_settings["servicename"]))
1124
    
28 by Teddy Hogeborn
* server.conf: New file.
1125
    # Parse config file with clients
1126
    client_defaults = { "timeout": "1h",
1127
                        "interval": "5m",
24.1.121 by Björn Påhlsson
mandos-ctl: Added support for all client calls
1128
                        "checker": "fping -q -- %%(host)s",
93 by Teddy Hogeborn
* mandos (string_to_delta): Accept a whitespace-separated sequence of
1129
                        "host": "",
28 by Teddy Hogeborn
* server.conf: New file.
1130
                        }
1131
    client_config = ConfigParser.SafeConfigParser(client_defaults)
1132
    client_config.read(os.path.join(server_settings["configdir"],
1133
                                    "clients.conf"))
327 by Teddy Hogeborn
Merge from pipe IPC branch.
1134
1135
    global mandos_dbus_service
1136
    mandos_dbus_service = None
28 by Teddy Hogeborn
* server.conf: New file.
1137
    
163 by Teddy Hogeborn
* Makefile (PIDDIR, USER, GROUP): Removed.
1138
    clients = Set()
1139
    tcp_server = IPv6_TCPServer((server_settings["address"],
1140
                                 server_settings["port"]),
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
1141
                                TCP_handler,
163 by Teddy Hogeborn
* Makefile (PIDDIR, USER, GROUP): Removed.
1142
                                settings=server_settings,
314 by Teddy Hogeborn
Support not using IPv6 in server:
1143
                                clients=clients, use_ipv6=use_ipv6)
164 by Teddy Hogeborn
* mandos: Open the PID file before daemonizing, but write to it
1144
    pidfilename = "/var/run/mandos.pid"
1145
    try:
1146
        pidfile = open(pidfilename, "w")
292 by Teddy Hogeborn
* Makefile (run-server): Use "--no-dbus" unconditionally.
1147
    except IOError:
164 by Teddy Hogeborn
* mandos: Open the PID file before daemonizing, but write to it
1148
        logger.error("Could not open file %r", pidfilename)
1149
    
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
1150
    try:
1151
        uid = pwd.getpwnam("_mandos").pw_uid
256 by Teddy Hogeborn
* mandos (main): Try to find non-privileged user+group in pairs, so
1152
        gid = pwd.getpwnam("_mandos").pw_gid
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
1153
    except KeyError:
1154
        try:
1155
            uid = pwd.getpwnam("mandos").pw_uid
256 by Teddy Hogeborn
* mandos (main): Try to find non-privileged user+group in pairs, so
1156
            gid = pwd.getpwnam("mandos").pw_gid
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
1157
        except KeyError:
1158
            try:
1159
                uid = pwd.getpwnam("nobody").pw_uid
256 by Teddy Hogeborn
* mandos (main): Try to find non-privileged user+group in pairs, so
1160
                gid = pwd.getpwnam("nogroup").pw_gid
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
1161
            except KeyError:
1162
                uid = 65534
1163
                gid = 65534
163 by Teddy Hogeborn
* Makefile (PIDDIR, USER, GROUP): Removed.
1164
    try:
290 by Teddy Hogeborn
* mandos (main): Bug fix: Do setgid before setuid. Add verbose GnuTLS
1165
        os.setgid(gid)
163 by Teddy Hogeborn
* Makefile (PIDDIR, USER, GROUP): Removed.
1166
        os.setuid(uid)
1167
    except OSError, error:
1168
        if error[0] != errno.EPERM:
1169
            raise error
164 by Teddy Hogeborn
* mandos: Open the PID file before daemonizing, but write to it
1170
    
290 by Teddy Hogeborn
* mandos (main): Bug fix: Do setgid before setuid. Add verbose GnuTLS
1171
    # Enable all possible GnuTLS debugging
1172
    if debug:
1173
        # "Use a log level over 10 to enable all debugging options."
1174
        # - GnuTLS manual
1175
        gnutls.library.functions.gnutls_global_set_log_level(11)
1176
        
1177
        @gnutls.library.types.gnutls_log_func
1178
        def debug_gnutls(level, string):
1179
            logger.debug("GnuTLS: %s", string[:-1])
1180
        
1181
        (gnutls.library.functions
1182
         .gnutls_global_set_log_function(debug_gnutls))
1183
    
28 by Teddy Hogeborn
* server.conf: New file.
1184
    global service
314 by Teddy Hogeborn
Support not using IPv6 in server:
1185
    protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
28 by Teddy Hogeborn
* server.conf: New file.
1186
    service = AvahiService(name = server_settings["servicename"],
314 by Teddy Hogeborn
Support not using IPv6 in server:
1187
                           servicetype = "_mandos._tcp",
1188
                           protocol = protocol)
29 by Teddy Hogeborn
* plugins.d/mandosclient.c (start_mandos_communication): Changed
1189
    if server_settings["interface"]:
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
1190
        service.interface = (if_nametoindex
1191
                             (server_settings["interface"]))
25 by Teddy Hogeborn
* mandos-clients.conf ([DEFAULT]): New section.
1192
    
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
1193
    global main_loop
1194
    global bus
1195
    global server
1196
    # From the Avahi example code
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
1197
    DBusGMainLoop(set_as_default=True )
1198
    main_loop = gobject.MainLoop()
1199
    bus = dbus.SystemBus()
109 by Teddy Hogeborn
* .bzrignore: New.
1200
    server = dbus.Interface(bus.get_object(avahi.DBUS_NAME,
1201
                                           avahi.DBUS_PATH_SERVER),
1202
                            avahi.DBUS_INTERFACE_SERVER)
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
1203
    # End of Avahi example code
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1204
    if use_dbus:
279 by Teddy Hogeborn
* mandos (Client.__init__): Disable D-Bus during init to avoid
1205
        bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos", bus)
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
1206
    
44 by Teddy Hogeborn
* ca.pem: Removed.
1207
    clients.update(Set(Client(name = section,
1208
                              config
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1209
                              = dict(client_config.items(section)),
1210
                              use_dbus = use_dbus)
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
1211
                       for section in client_config.sections()))
51 by Teddy Hogeborn
* clients.conf: Better comments.
1212
    if not clients:
244 by Teddy Hogeborn
* debian/control (Build-Depends): Bug fix: Added "docbook-xml".
1213
        logger.warning(u"No clients defined")
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
1214
    
94 by Teddy Hogeborn
* clients.conf ([DEFAULT]/checker): Update to new default value.
1215
    if debug:
1216
        # Redirect stdin so all checkers get /dev/null
1217
        null = os.open(os.path.devnull, os.O_NOCTTY | os.O_RDWR)
1218
        os.dup2(null, sys.stdin.fileno())
1219
        if null > 2:
1220
            os.close(null)
1221
    else:
1222
        # No console logging
61 by Teddy Hogeborn
* mandos (console): Define handler globally.
1223
        logger.removeHandler(console)
94 by Teddy Hogeborn
* clients.conf ([DEFAULT]/checker): Update to new default value.
1224
        # Close all input and output, do double fork, etc.
47 by Teddy Hogeborn
* plugbasedclient.c: Renamed to "mandos-client.c". All users changed.
1225
        daemon()
51 by Teddy Hogeborn
* clients.conf: Better comments.
1226
    
165 by Teddy Hogeborn
* mandos (main): Use EAFP with pidfile.
1227
    try:
327 by Teddy Hogeborn
Merge from pipe IPC branch.
1228
        with closing(pidfile):
1229
            pid = os.getpid()
1230
            pidfile.write(str(pid) + "\n")
165 by Teddy Hogeborn
* mandos (main): Use EAFP with pidfile.
1231
        del pidfile
215 by Teddy Hogeborn
* mandos: Remove unused "select" module. Import "ctypes.util".
1232
    except IOError:
165 by Teddy Hogeborn
* mandos (main): Use EAFP with pidfile.
1233
        logger.error(u"Could not write to file %r with PID %d",
1234
                     pidfilename, pid)
1235
    except NameError:
1236
        # "pidfile" was never created
1237
        pass
164 by Teddy Hogeborn
* mandos: Open the PID file before daemonizing, but write to it
1238
    del pidfilename
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
1239
    
1240
    def cleanup():
1241
        "Cleanup function; run on exit"
1242
        global group
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
1243
        # From the Avahi example code
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
1244
        if not group is None:
1245
            group.Free()
1246
            group = None
1247
        # End of Avahi example code
1248
        
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
1249
        while clients:
1250
            client = clients.pop()
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
1251
            client.disable_hook = None
1252
            client.disable()
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
1253
    
1254
    atexit.register(cleanup)
1255
    
1256
    if not debug:
1257
        signal.signal(signal.SIGINT, signal.SIG_IGN)
28 by Teddy Hogeborn
* server.conf: New file.
1258
    signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
1259
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
1260
    
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1261
    if use_dbus:
327 by Teddy Hogeborn
Merge from pipe IPC branch.
1262
        class MandosDBusService(dbus.service.Object):
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1263
            """A D-Bus proxy object"""
1264
            def __init__(self):
279 by Teddy Hogeborn
* mandos (Client.__init__): Disable D-Bus during init to avoid
1265
                dbus.service.Object.__init__(self, bus, "/")
1266
            _interface = u"se.bsnet.fukt.Mandos"
278 by Teddy Hogeborn
* mandos (Client.GetAllProperties): Also send Client.dbus_object_path
1267
            
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1268
            @dbus.service.signal(_interface, signature="oa{sv}")
1269
            def ClientAdded(self, objpath, properties):
1270
                "D-Bus signal"
1271
                pass
278 by Teddy Hogeborn
* mandos (Client.GetAllProperties): Also send Client.dbus_object_path
1272
            
327 by Teddy Hogeborn
Merge from pipe IPC branch.
1273
            @dbus.service.signal(_interface, signature="s")
1274
            def ClientNotFound(self, fingerprint):
1275
                "D-Bus signal"
1276
                pass
1277
            
278 by Teddy Hogeborn
* mandos (Client.GetAllProperties): Also send Client.dbus_object_path
1278
            @dbus.service.signal(_interface, signature="os")
1279
            def ClientRemoved(self, objpath, name):
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1280
                "D-Bus signal"
1281
                pass
278 by Teddy Hogeborn
* mandos (Client.GetAllProperties): Also send Client.dbus_object_path
1282
            
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1283
            @dbus.service.method(_interface, out_signature="ao")
1284
            def GetAllClients(self):
283 by Teddy Hogeborn
* mandos (peer_certificate): Handle NULL pointer from
1285
                "D-Bus method"
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1286
                return dbus.Array(c.dbus_object_path for c in clients)
278 by Teddy Hogeborn
* mandos (Client.GetAllProperties): Also send Client.dbus_object_path
1287
            
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1288
            @dbus.service.method(_interface, out_signature="a{oa{sv}}")
1289
            def GetAllClientsWithProperties(self):
283 by Teddy Hogeborn
* mandos (peer_certificate): Handle NULL pointer from
1290
                "D-Bus method"
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1291
                return dbus.Dictionary(
1292
                    ((c.dbus_object_path, c.GetAllProperties())
1293
                     for c in clients),
1294
                    signature="oa{sv}")
278 by Teddy Hogeborn
* mandos (Client.GetAllProperties): Also send Client.dbus_object_path
1295
            
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1296
            @dbus.service.method(_interface, in_signature="o")
1297
            def RemoveClient(self, object_path):
283 by Teddy Hogeborn
* mandos (peer_certificate): Handle NULL pointer from
1298
                "D-Bus method"
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1299
                for c in clients:
1300
                    if c.dbus_object_path == object_path:
1301
                        clients.remove(c)
1302
                        # Don't signal anything except ClientRemoved
1303
                        c.use_dbus = False
1304
                        c.disable()
1305
                        # Emit D-Bus signal
278 by Teddy Hogeborn
* mandos (Client.GetAllProperties): Also send Client.dbus_object_path
1306
                        self.ClientRemoved(object_path, c.name)
1307
                        return
1308
                raise KeyError
1309
            
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1310
            del _interface
278 by Teddy Hogeborn
* mandos (Client.GetAllProperties): Also send Client.dbus_object_path
1311
        
327 by Teddy Hogeborn
Merge from pipe IPC branch.
1312
        mandos_dbus_service = MandosDBusService()
238 by Teddy Hogeborn
First version of a somewhat complete D-Bus server interface. Also
1313
    
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
1314
    for client in clients:
243 by Teddy Hogeborn
* mandos (Client.timeout, Client.interval): Changed from being a
1315
        if use_dbus:
1316
            # Emit D-Bus signal
327 by Teddy Hogeborn
Merge from pipe IPC branch.
1317
            mandos_dbus_service.ClientAdded(client.dbus_object_path,
1318
                                            client.GetAllProperties())
239 by Teddy Hogeborn
* mandos (_datetime_to_dbus_struct): Renamed to "_datetime_to_dbus";
1319
        client.enable()
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
1320
    
163 by Teddy Hogeborn
* Makefile (PIDDIR, USER, GROUP): Removed.
1321
    tcp_server.enable()
1322
    tcp_server.server_activate()
1323
    
28 by Teddy Hogeborn
* server.conf: New file.
1324
    # Find out what port we got
1325
    service.port = tcp_server.socket.getsockname()[1]
314 by Teddy Hogeborn
Support not using IPv6 in server:
1326
    if use_ipv6:
1327
        logger.info(u"Now listening on address %r, port %d,"
1328
                    " flowinfo %d, scope_id %d"
1329
                    % tcp_server.socket.getsockname())
1330
    else:                       # IPv4
1331
        logger.info(u"Now listening on address %r, port %d"
1332
                    % tcp_server.socket.getsockname())
28 by Teddy Hogeborn
* server.conf: New file.
1333
    
29 by Teddy Hogeborn
* plugins.d/mandosclient.c (start_mandos_communication): Changed
1334
    #service.interface = tcp_server.socket.getsockname()[3]
28 by Teddy Hogeborn
* server.conf: New file.
1335
    
1336
    try:
1337
        # From the Avahi example code
1338
        server.connect_to_signal("StateChanged", server_state_changed)
1339
        try:
1340
            server_state_changed(server.GetState())
1341
        except dbus.exceptions.DBusException, error:
1342
            logger.critical(u"DBusException: %s", error)
1343
            sys.exit(1)
1344
        # End of Avahi example code
1345
        
1346
        gobject.io_add_watch(tcp_server.fileno(), gobject.IO_IN,
1347
                             lambda *args, **kwargs:
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
1348
                             (tcp_server.handle_request
1349
                              (*args[2:], **kwargs) or True))
28 by Teddy Hogeborn
* server.conf: New file.
1350
        
51 by Teddy Hogeborn
* clients.conf: Better comments.
1351
        logger.debug(u"Starting main loop")
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
1352
        main_loop.run()
28 by Teddy Hogeborn
* server.conf: New file.
1353
    except AvahiError, error:
242 by Teddy Hogeborn
* mandos (AvahiError): Converted to use unicode. All users changed.
1354
        logger.critical(u"AvahiError: %s", error)
28 by Teddy Hogeborn
* server.conf: New file.
1355
        sys.exit(1)
11 by Teddy Hogeborn
* server.py: Rewritten to use Zeroconf (mDNS/DNS-SD) in place of the
1356
    except KeyboardInterrupt:
15 by Teddy Hogeborn
* mandos-clients.conf ([foo]): Uncommented.
1357
        if debug:
292 by Teddy Hogeborn
* Makefile (run-server): Use "--no-dbus" unconditionally.
1358
            print >> sys.stderr
1359
        logger.debug("Server received KeyboardInterrupt")
1360
    logger.debug("Server exiting")
16 by Teddy Hogeborn
* Makefile: Include targets for all binaries.
1361
1362
if __name__ == '__main__':
1363
    main()