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