196
265
                       .replace(b"\n", b"\\n")
 
197
266
                       .replace(b"\0", b"\\x00"))
 
200
269
    def encrypt(self, data, password):
 
201
270
        passphrase = self.password_encode(password)
 
202
271
        with tempfile.NamedTemporaryFile(
 
203
272
                dir=self.tempdir) as passfile:
 
204
273
            passfile.write(passphrase)
 
206
 
            proc = subprocess.Popen(['gpg', '--symmetric',
 
 
275
            proc = subprocess.Popen([self.gpg, '--symmetric',
 
207
276
                                     '--passphrase-file',
 
209
278
                                    + self.gnupgargs,
 
210
 
                                    stdin = subprocess.PIPE,
 
211
 
                                    stdout = subprocess.PIPE,
 
212
 
                                    stderr = subprocess.PIPE)
 
213
 
            ciphertext, err = proc.communicate(input = data)
 
 
279
                                    stdin=subprocess.PIPE,
 
 
280
                                    stdout=subprocess.PIPE,
 
 
281
                                    stderr=subprocess.PIPE)
 
 
282
            ciphertext, err = proc.communicate(input=data)
 
214
283
        if proc.returncode != 0:
 
215
284
            raise PGPError(err)
 
216
285
        return ciphertext
 
218
287
    def decrypt(self, data, password):
 
219
288
        passphrase = self.password_encode(password)
 
220
289
        with tempfile.NamedTemporaryFile(
 
221
 
                dir = self.tempdir) as passfile:
 
 
290
                dir=self.tempdir) as passfile:
 
222
291
            passfile.write(passphrase)
 
224
 
            proc = subprocess.Popen(['gpg', '--decrypt',
 
 
293
            proc = subprocess.Popen([self.gpg, '--decrypt',
 
225
294
                                     '--passphrase-file',
 
227
296
                                    + self.gnupgargs,
 
228
 
                                    stdin = subprocess.PIPE,
 
229
 
                                    stdout = subprocess.PIPE,
 
230
 
                                    stderr = subprocess.PIPE)
 
231
 
            decrypted_plaintext, err = proc.communicate(input = data)
 
 
297
                                    stdin=subprocess.PIPE,
 
 
298
                                    stdout=subprocess.PIPE,
 
 
299
                                    stderr=subprocess.PIPE)
 
 
300
            decrypted_plaintext, err = proc.communicate(input=data)
 
232
301
        if proc.returncode != 0:
 
233
302
            raise PGPError(err)
 
234
303
        return decrypted_plaintext
 
 
306
# Pretend that we have an Avahi module
 
 
308
    """This isn't so much a class as it is a module-like namespace."""
 
 
309
    IF_UNSPEC = -1               # avahi-common/address.h
 
 
310
    PROTO_UNSPEC = -1            # avahi-common/address.h
 
 
311
    PROTO_INET = 0               # avahi-common/address.h
 
 
312
    PROTO_INET6 = 1              # avahi-common/address.h
 
 
313
    DBUS_NAME = "org.freedesktop.Avahi"
 
 
314
    DBUS_INTERFACE_ENTRY_GROUP = DBUS_NAME + ".EntryGroup"
 
 
315
    DBUS_INTERFACE_SERVER = DBUS_NAME + ".Server"
 
 
316
    DBUS_PATH_SERVER = "/"
 
 
319
    def string_array_to_txt_array(t):
 
 
320
        return dbus.Array((dbus.ByteArray(s.encode("utf-8"))
 
 
321
                           for s in t), signature="ay")
 
 
322
    ENTRY_GROUP_ESTABLISHED = 2  # avahi-common/defs.h
 
 
323
    ENTRY_GROUP_COLLISION = 3    # avahi-common/defs.h
 
 
324
    ENTRY_GROUP_FAILURE = 4      # avahi-common/defs.h
 
 
325
    SERVER_INVALID = 0           # avahi-common/defs.h
 
 
326
    SERVER_REGISTERING = 1       # avahi-common/defs.h
 
 
327
    SERVER_RUNNING = 2           # avahi-common/defs.h
 
 
328
    SERVER_COLLISION = 3         # avahi-common/defs.h
 
 
329
    SERVER_FAILURE = 4           # avahi-common/defs.h
 
237
332
class AvahiError(Exception):
 
238
333
    def __init__(self, value, *args, **kwargs):
 
239
334
        self.value = value
 
 
418
524
class AvahiServiceToSyslog(AvahiService):
 
419
525
    def rename(self, *args, **kwargs):
 
420
526
        """Add the new name to the syslog messages"""
 
421
 
        ret = AvahiService.rename(self, *args, **kwargs)
 
 
527
        ret = super(AvahiServiceToSyslog, self).rename(*args,
 
422
529
        syslogger.setFormatter(logging.Formatter(
 
423
530
            'Mandos ({}) [%(process)d]: %(levelname)s: %(message)s'
 
424
531
            .format(self.name)))
 
 
535
# Pretend that we have a GnuTLS module
 
 
537
    """This isn't so much a class as it is a module-like namespace."""
 
 
539
    library = ctypes.util.find_library("gnutls")
 
 
541
        library = ctypes.util.find_library("gnutls-deb0")
 
 
542
    _library = ctypes.cdll.LoadLibrary(library)
 
 
545
    # Unless otherwise indicated, the constants and types below are
 
 
546
    # all from the gnutls/gnutls.h C header file.
 
 
557
    E_NO_CERTIFICATE_FOUND = -49
 
 
562
    KEYID_USE_SHA256 = 1        # gnutls/x509.h
 
 
563
    OPENPGP_FMT_RAW = 0         # gnutls/openpgp.h
 
 
566
    class session_int(ctypes.Structure):
 
 
568
    session_t = ctypes.POINTER(session_int)
 
 
570
    class certificate_credentials_st(ctypes.Structure):
 
 
572
    certificate_credentials_t = ctypes.POINTER(
 
 
573
        certificate_credentials_st)
 
 
574
    certificate_type_t = ctypes.c_int
 
 
576
    class datum_t(ctypes.Structure):
 
 
577
        _fields_ = [('data', ctypes.POINTER(ctypes.c_ubyte)),
 
 
578
                    ('size', ctypes.c_uint)]
 
 
580
    class openpgp_crt_int(ctypes.Structure):
 
 
582
    openpgp_crt_t = ctypes.POINTER(openpgp_crt_int)
 
 
583
    openpgp_crt_fmt_t = ctypes.c_int  # gnutls/openpgp.h
 
 
584
    log_func = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
 
 
585
    credentials_type_t = ctypes.c_int
 
 
586
    transport_ptr_t = ctypes.c_void_p
 
 
587
    close_request_t = ctypes.c_int
 
 
590
    class Error(Exception):
 
 
591
        def __init__(self, message=None, code=None, args=()):
 
 
592
            # Default usage is by a message string, but if a return
 
 
593
            # code is passed, convert it to a string with
 
 
596
            if message is None and code is not None:
 
 
597
                message = gnutls.strerror(code)
 
 
598
            return super(gnutls.Error, self).__init__(
 
 
601
    class CertificateSecurityError(Error):
 
 
607
            self._c_object = gnutls.certificate_credentials_t()
 
 
608
            gnutls.certificate_allocate_credentials(
 
 
609
                ctypes.byref(self._c_object))
 
 
610
            self.type = gnutls.CRD_CERTIFICATE
 
 
613
            gnutls.certificate_free_credentials(self._c_object)
 
 
616
        def __init__(self, socket, credentials=None):
 
 
617
            self._c_object = gnutls.session_t()
 
 
618
            gnutls_flags = gnutls.CLIENT
 
 
619
            if gnutls.check_version(b"3.5.6"):
 
 
620
                gnutls_flags |= gnutls.NO_TICKETS
 
 
622
                gnutls_flags |= gnutls.ENABLE_RAWPK
 
 
623
            gnutls.init(ctypes.byref(self._c_object), gnutls_flags)
 
 
625
            gnutls.set_default_priority(self._c_object)
 
 
626
            gnutls.transport_set_ptr(self._c_object, socket.fileno())
 
 
627
            gnutls.handshake_set_private_extensions(self._c_object,
 
 
630
            if credentials is None:
 
 
631
                credentials = gnutls.Credentials()
 
 
632
            gnutls.credentials_set(self._c_object, credentials.type,
 
 
633
                                   ctypes.cast(credentials._c_object,
 
 
635
            self.credentials = credentials
 
 
638
            gnutls.deinit(self._c_object)
 
 
641
            return gnutls.handshake(self._c_object)
 
 
643
        def send(self, data):
 
 
647
                data_len -= gnutls.record_send(self._c_object,
 
 
652
            return gnutls.bye(self._c_object, gnutls.SHUT_RDWR)
 
 
654
    # Error handling functions
 
 
655
    def _error_code(result):
 
 
656
        """A function to raise exceptions on errors, suitable
 
 
657
        for the 'restype' attribute on ctypes functions"""
 
 
660
        if result == gnutls.E_NO_CERTIFICATE_FOUND:
 
 
661
            raise gnutls.CertificateSecurityError(code=result)
 
 
662
        raise gnutls.Error(code=result)
 
 
664
    def _retry_on_error(result, func, arguments):
 
 
665
        """A function to retry on some errors, suitable
 
 
666
        for the 'errcheck' attribute on ctypes functions"""
 
 
668
            if result not in (gnutls.E_INTERRUPTED, gnutls.E_AGAIN):
 
 
669
                return _error_code(result)
 
 
670
            result = func(*arguments)
 
 
673
    # Unless otherwise indicated, the function declarations below are
 
 
674
    # all from the gnutls/gnutls.h C header file.
 
 
677
    priority_set_direct = _library.gnutls_priority_set_direct
 
 
678
    priority_set_direct.argtypes = [session_t, ctypes.c_char_p,
 
 
679
                                    ctypes.POINTER(ctypes.c_char_p)]
 
 
680
    priority_set_direct.restype = _error_code
 
 
682
    init = _library.gnutls_init
 
 
683
    init.argtypes = [ctypes.POINTER(session_t), ctypes.c_int]
 
 
684
    init.restype = _error_code
 
 
686
    set_default_priority = _library.gnutls_set_default_priority
 
 
687
    set_default_priority.argtypes = [session_t]
 
 
688
    set_default_priority.restype = _error_code
 
 
690
    record_send = _library.gnutls_record_send
 
 
691
    record_send.argtypes = [session_t, ctypes.c_void_p,
 
 
693
    record_send.restype = ctypes.c_ssize_t
 
 
694
    record_send.errcheck = _retry_on_error
 
 
696
    certificate_allocate_credentials = (
 
 
697
        _library.gnutls_certificate_allocate_credentials)
 
 
698
    certificate_allocate_credentials.argtypes = [
 
 
699
        ctypes.POINTER(certificate_credentials_t)]
 
 
700
    certificate_allocate_credentials.restype = _error_code
 
 
702
    certificate_free_credentials = (
 
 
703
        _library.gnutls_certificate_free_credentials)
 
 
704
    certificate_free_credentials.argtypes = [
 
 
705
        certificate_credentials_t]
 
 
706
    certificate_free_credentials.restype = None
 
 
708
    handshake_set_private_extensions = (
 
 
709
        _library.gnutls_handshake_set_private_extensions)
 
 
710
    handshake_set_private_extensions.argtypes = [session_t,
 
 
712
    handshake_set_private_extensions.restype = None
 
 
714
    credentials_set = _library.gnutls_credentials_set
 
 
715
    credentials_set.argtypes = [session_t, credentials_type_t,
 
 
717
    credentials_set.restype = _error_code
 
 
719
    strerror = _library.gnutls_strerror
 
 
720
    strerror.argtypes = [ctypes.c_int]
 
 
721
    strerror.restype = ctypes.c_char_p
 
 
723
    certificate_type_get = _library.gnutls_certificate_type_get
 
 
724
    certificate_type_get.argtypes = [session_t]
 
 
725
    certificate_type_get.restype = _error_code
 
 
727
    certificate_get_peers = _library.gnutls_certificate_get_peers
 
 
728
    certificate_get_peers.argtypes = [session_t,
 
 
729
                                      ctypes.POINTER(ctypes.c_uint)]
 
 
730
    certificate_get_peers.restype = ctypes.POINTER(datum_t)
 
 
732
    global_set_log_level = _library.gnutls_global_set_log_level
 
 
733
    global_set_log_level.argtypes = [ctypes.c_int]
 
 
734
    global_set_log_level.restype = None
 
 
736
    global_set_log_function = _library.gnutls_global_set_log_function
 
 
737
    global_set_log_function.argtypes = [log_func]
 
 
738
    global_set_log_function.restype = None
 
 
740
    deinit = _library.gnutls_deinit
 
 
741
    deinit.argtypes = [session_t]
 
 
742
    deinit.restype = None
 
 
744
    handshake = _library.gnutls_handshake
 
 
745
    handshake.argtypes = [session_t]
 
 
746
    handshake.restype = _error_code
 
 
747
    handshake.errcheck = _retry_on_error
 
 
749
    transport_set_ptr = _library.gnutls_transport_set_ptr
 
 
750
    transport_set_ptr.argtypes = [session_t, transport_ptr_t]
 
 
751
    transport_set_ptr.restype = None
 
 
753
    bye = _library.gnutls_bye
 
 
754
    bye.argtypes = [session_t, close_request_t]
 
 
755
    bye.restype = _error_code
 
 
756
    bye.errcheck = _retry_on_error
 
 
758
    check_version = _library.gnutls_check_version
 
 
759
    check_version.argtypes = [ctypes.c_char_p]
 
 
760
    check_version.restype = ctypes.c_char_p
 
 
762
    _need_version = b"3.3.0"
 
 
763
    if check_version(_need_version) is None:
 
 
764
        raise self.Error("Needs GnuTLS {} or later"
 
 
765
                         .format(_need_version))
 
 
767
    _tls_rawpk_version = b"3.6.6"
 
 
768
    has_rawpk = bool(check_version(_tls_rawpk_version))
 
 
772
        class pubkey_st(ctypes.Structure):
 
 
774
        pubkey_t = ctypes.POINTER(pubkey_st)
 
 
776
        x509_crt_fmt_t = ctypes.c_int
 
 
778
        # All the function declarations below are from
 
 
780
        pubkey_init = _library.gnutls_pubkey_init
 
 
781
        pubkey_init.argtypes = [ctypes.POINTER(pubkey_t)]
 
 
782
        pubkey_init.restype = _error_code
 
 
784
        pubkey_import = _library.gnutls_pubkey_import
 
 
785
        pubkey_import.argtypes = [pubkey_t, ctypes.POINTER(datum_t),
 
 
787
        pubkey_import.restype = _error_code
 
 
789
        pubkey_get_key_id = _library.gnutls_pubkey_get_key_id
 
 
790
        pubkey_get_key_id.argtypes = [pubkey_t, ctypes.c_int,
 
 
791
                                      ctypes.POINTER(ctypes.c_ubyte),
 
 
792
                                      ctypes.POINTER(ctypes.c_size_t)]
 
 
793
        pubkey_get_key_id.restype = _error_code
 
 
795
        pubkey_deinit = _library.gnutls_pubkey_deinit
 
 
796
        pubkey_deinit.argtypes = [pubkey_t]
 
 
797
        pubkey_deinit.restype = None
 
 
799
        # All the function declarations below are from
 
 
802
        openpgp_crt_init = _library.gnutls_openpgp_crt_init
 
 
803
        openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
 
 
804
        openpgp_crt_init.restype = _error_code
 
 
806
        openpgp_crt_import = _library.gnutls_openpgp_crt_import
 
 
807
        openpgp_crt_import.argtypes = [openpgp_crt_t,
 
 
808
                                       ctypes.POINTER(datum_t),
 
 
810
        openpgp_crt_import.restype = _error_code
 
 
812
        openpgp_crt_verify_self = \
 
 
813
            _library.gnutls_openpgp_crt_verify_self
 
 
814
        openpgp_crt_verify_self.argtypes = [
 
 
817
            ctypes.POINTER(ctypes.c_uint),
 
 
819
        openpgp_crt_verify_self.restype = _error_code
 
 
821
        openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
 
 
822
        openpgp_crt_deinit.argtypes = [openpgp_crt_t]
 
 
823
        openpgp_crt_deinit.restype = None
 
 
825
        openpgp_crt_get_fingerprint = (
 
 
826
            _library.gnutls_openpgp_crt_get_fingerprint)
 
 
827
        openpgp_crt_get_fingerprint.argtypes = [openpgp_crt_t,
 
 
831
        openpgp_crt_get_fingerprint.restype = _error_code
 
 
833
    if check_version(b"3.6.4"):
 
 
834
        certificate_type_get2 = _library.gnutls_certificate_type_get2
 
 
835
        certificate_type_get2.argtypes = [session_t, ctypes.c_int]
 
 
836
        certificate_type_get2.restype = _error_code
 
 
838
    # Remove non-public functions
 
 
839
    del _error_code, _retry_on_error
 
427
842
def call_pipe(connection,       # : multiprocessing.Connection
 
428
843
              func, *args, **kwargs):
 
429
844
    """This function is meant to be called by multiprocessing.Process
 
431
846
    This function runs func(*args, **kwargs), and writes the resulting
 
432
847
    return value on the provided multiprocessing.Connection.
 
434
849
    connection.send(func(*args, **kwargs))
 
435
850
    connection.close()
 
437
 
class Client(object):
 
438
854
    """A representation of a client host served by this server.
 
441
857
    approved:   bool(); 'None' if not yet approved/disapproved
 
442
858
    approval_delay: datetime.timedelta(); Time to wait for approval
 
443
859
    approval_duration: datetime.timedelta(); Duration of one approval
 
444
 
    checker:    subprocess.Popen(); a running checker process used
 
445
 
                                    to see if the client lives.
 
446
 
                                    'None' if no process is running.
 
447
 
    checker_callback_tag: a gobject event source tag, or None
 
 
860
    checker: multiprocessing.Process(); a running checker process used
 
 
861
             to see if the client lives. 'None' if no process is
 
 
863
    checker_callback_tag: a GLib event source tag, or None
 
448
864
    checker_command: string; External command which is run to check
 
449
865
                     if client lives.  %() expansions are done at
 
450
866
                     runtime with vars(self) as dict, so that for
 
451
867
                     instance %(name)s can be used in the command.
 
452
 
    checker_initiator_tag: a gobject event source tag, or None
 
 
868
    checker_initiator_tag: a GLib event source tag, or None
 
453
869
    created:    datetime.datetime(); (UTC) object creation
 
454
870
    client_structure: Object describing what attributes a client has
 
455
871
                      and is used for storing the client at exit
 
456
872
    current_checker_command: string; current running checker_command
 
457
 
    disable_initiator_tag: a gobject event source tag, or None
 
 
873
    disable_initiator_tag: a GLib event source tag, or None
 
459
875
    fingerprint: string (40 or 32 hexadecimal digits); used to
 
460
 
                 uniquely identify the client
 
 
876
                 uniquely identify an OpenPGP client
 
 
877
    key_id: string (64 hexadecimal digits); used to uniquely identify
 
 
878
            a client using raw public keys
 
461
879
    host:       string; available for use by the checker command
 
462
880
    interval:   datetime.timedelta(); How often to start a new checker
 
463
881
    last_approval_request: datetime.datetime(); (UTC) or None
 
 
884
1312
                for cls in self.__class__.__mro__
 
885
1313
                for name, athing in
 
886
1314
                inspect.getmembers(cls, self._is_dbus_thing(thing)))
 
 
1316
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
 
 
1318
                         path_keyword='object_path',
 
 
1319
                         connection_keyword='connection')
 
 
1320
    def Introspect(self, object_path, connection):
 
 
1321
        """Overloading of standard D-Bus method.
 
 
1323
        Inserts annotation tags on methods and signals.
 
 
1325
        xmlstring = dbus.service.Object.Introspect(self, object_path,
 
 
1328
            document = xml.dom.minidom.parseString(xmlstring)
 
 
1330
            for if_tag in document.getElementsByTagName("interface"):
 
 
1331
                # Add annotation tags
 
 
1332
                for typ in ("method", "signal"):
 
 
1333
                    for tag in if_tag.getElementsByTagName(typ):
 
 
1335
                        for name, prop in (self.
 
 
1336
                                           _get_all_dbus_things(typ)):
 
 
1337
                            if (name == tag.getAttribute("name")
 
 
1338
                                and prop._dbus_interface
 
 
1339
                                == if_tag.getAttribute("name")):
 
 
1340
                                annots.update(getattr(
 
 
1341
                                    prop, "_dbus_annotations", {}))
 
 
1342
                        for name, value in annots.items():
 
 
1343
                            ann_tag = document.createElement(
 
 
1345
                            ann_tag.setAttribute("name", name)
 
 
1346
                            ann_tag.setAttribute("value", value)
 
 
1347
                            tag.appendChild(ann_tag)
 
 
1348
                # Add interface annotation tags
 
 
1349
                for annotation, value in dict(
 
 
1350
                    itertools.chain.from_iterable(
 
 
1351
                        annotations().items()
 
 
1352
                        for name, annotations
 
 
1353
                        in self._get_all_dbus_things("interface")
 
 
1354
                        if name == if_tag.getAttribute("name")
 
 
1356
                    ann_tag = document.createElement("annotation")
 
 
1357
                    ann_tag.setAttribute("name", annotation)
 
 
1358
                    ann_tag.setAttribute("value", value)
 
 
1359
                    if_tag.appendChild(ann_tag)
 
 
1360
                # Fix argument name for the Introspect method itself
 
 
1361
                if (if_tag.getAttribute("name")
 
 
1362
                    == dbus.INTROSPECTABLE_IFACE):
 
 
1363
                    for cn in if_tag.getElementsByTagName("method"):
 
 
1364
                        if cn.getAttribute("name") == "Introspect":
 
 
1365
                            for arg in cn.getElementsByTagName("arg"):
 
 
1366
                                if (arg.getAttribute("direction")
 
 
1368
                                    arg.setAttribute("name",
 
 
1370
            xmlstring = document.toxml("utf-8")
 
 
1372
        except (AttributeError, xml.dom.DOMException,
 
 
1373
                xml.parsers.expat.ExpatError) as error:
 
 
1374
            logger.error("Failed to override Introspection method",
 
 
1379
class DBusObjectWithProperties(DBusObjectWithAnnotations):
 
 
1380
    """A D-Bus object with properties.
 
 
1382
    Classes inheriting from this can use the dbus_service_property
 
 
1383
    decorator to expose methods as D-Bus properties.  It exposes the
 
 
1384
    standard Get(), Set(), and GetAll() methods on the D-Bus.
 
888
1387
    def _get_dbus_property(self, interface_name, property_name):
 
889
1388
        """Returns a bound method if one exists which is a D-Bus
 
890
1389
        property with the specified name and interface.
 
 
1048
1543
        return xmlstring
 
 
1547
    dbus.OBJECT_MANAGER_IFACE
 
 
1548
except AttributeError:
 
 
1549
    dbus.OBJECT_MANAGER_IFACE = "org.freedesktop.DBus.ObjectManager"
 
 
1552
class DBusObjectWithObjectManager(DBusObjectWithAnnotations):
 
 
1553
    """A D-Bus object with an ObjectManager.
 
 
1555
    Classes inheriting from this exposes the standard
 
 
1556
    GetManagedObjects call and the InterfacesAdded and
 
 
1557
    InterfacesRemoved signals on the standard
 
 
1558
    "org.freedesktop.DBus.ObjectManager" interface.
 
 
1560
    Note: No signals are sent automatically; they must be sent
 
 
1563
    @dbus.service.method(dbus.OBJECT_MANAGER_IFACE,
 
 
1564
                         out_signature="a{oa{sa{sv}}}")
 
 
1565
    def GetManagedObjects(self):
 
 
1566
        """This function must be overridden"""
 
 
1567
        raise NotImplementedError()
 
 
1569
    @dbus.service.signal(dbus.OBJECT_MANAGER_IFACE,
 
 
1570
                         signature="oa{sa{sv}}")
 
 
1571
    def InterfacesAdded(self, object_path, interfaces_and_properties):
 
 
1574
    @dbus.service.signal(dbus.OBJECT_MANAGER_IFACE, signature="oas")
 
 
1575
    def InterfacesRemoved(self, object_path, interfaces):
 
 
1578
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
 
 
1580
                         path_keyword='object_path',
 
 
1581
                         connection_keyword='connection')
 
 
1582
    def Introspect(self, object_path, connection):
 
 
1583
        """Overloading of standard D-Bus method.
 
 
1585
        Override return argument name of GetManagedObjects to be
 
 
1586
        "objpath_interfaces_and_properties"
 
 
1588
        xmlstring = DBusObjectWithAnnotations.Introspect(self,
 
 
1592
            document = xml.dom.minidom.parseString(xmlstring)
 
 
1594
            for if_tag in document.getElementsByTagName("interface"):
 
 
1595
                # Fix argument name for the GetManagedObjects method
 
 
1596
                if (if_tag.getAttribute("name")
 
 
1597
                    == dbus.OBJECT_MANAGER_IFACE):
 
 
1598
                    for cn in if_tag.getElementsByTagName("method"):
 
 
1599
                        if (cn.getAttribute("name")
 
 
1600
                            == "GetManagedObjects"):
 
 
1601
                            for arg in cn.getElementsByTagName("arg"):
 
 
1602
                                if (arg.getAttribute("direction")
 
 
1606
                                        "objpath_interfaces"
 
 
1608
            xmlstring = document.toxml("utf-8")
 
 
1610
        except (AttributeError, xml.dom.DOMException,
 
 
1611
                xml.parsers.expat.ExpatError) as error:
 
 
1612
            logger.error("Failed to override Introspection method",
 
1051
1617
def datetime_to_dbus(dt, variant_level=0):
 
1052
1618
    """Convert a UTC datetime.datetime() to a D-Bus type."""
 
1054
 
        return dbus.String("", variant_level = variant_level)
 
 
1620
        return dbus.String("", variant_level=variant_level)
 
1055
1621
    return dbus.String(dt.isoformat(), variant_level=variant_level)
 
 
1819
2405
                        delay -= time2 - time
 
1822
 
                while sent_size < len(client.secret):
 
1824
 
                        sent = session.send(client.secret[sent_size:])
 
1825
 
                    except gnutls.errors.GNUTLSError as error:
 
1826
 
                        logger.warning("gnutls send failed",
 
1829
 
                    logger.debug("Sent: %d, remaining: %d", sent,
 
1830
 
                                 len(client.secret) - (sent_size
 
 
2408
                    session.send(client.secret)
 
 
2409
                except gnutls.Error as error:
 
 
2410
                    logger.warning("gnutls send failed",
 
1834
2414
                logger.info("Sending secret to %s", client.name)
 
1835
2415
                # bump the timeout using extended_timeout
 
1836
2416
                client.bump_timeout(client.extended_timeout)
 
1837
2417
                if self.server.use_dbus:
 
1838
2418
                    # Emit D-Bus signal
 
1839
2419
                    client.GotSecret()
 
1842
2422
                if approval_required:
 
1843
2423
                    client.approvals_pending -= 1
 
1846
 
                except gnutls.errors.GNUTLSError as error:
 
 
2426
                except gnutls.Error as error:
 
1847
2427
                    logger.warning("GnuTLS bye failed",
 
1848
2428
                                   exc_info=error)
 
1851
2431
    def peer_certificate(session):
 
1852
 
        "Return the peer's OpenPGP certificate as a bytestring"
 
1853
 
        # If not an OpenPGP certificate...
 
1854
 
        if (gnutls.library.functions.gnutls_certificate_type_get(
 
1856
 
            != gnutls.library.constants.GNUTLS_CRT_OPENPGP):
 
1857
 
            # ...do the normal thing
 
1858
 
            return session.peer_certificate
 
 
2432
        "Return the peer's certificate as a bytestring"
 
 
2434
            cert_type = gnutls.certificate_type_get2(session._c_object,
 
 
2436
        except AttributeError:
 
 
2437
            cert_type = gnutls.certificate_type_get(session._c_object)
 
 
2438
        if gnutls.has_rawpk:
 
 
2439
            valid_cert_types = frozenset((gnutls.CRT_RAWPK,))
 
 
2441
            valid_cert_types = frozenset((gnutls.CRT_OPENPGP,))
 
 
2442
        # If not a valid certificate type...
 
 
2443
        if cert_type not in valid_cert_types:
 
 
2444
            logger.info("Cert type %r not in %r", cert_type,
 
 
2446
            # ...return invalid data
 
1859
2448
        list_size = ctypes.c_uint(1)
 
1860
 
        cert_list = (gnutls.library.functions
 
1861
 
                     .gnutls_certificate_get_peers
 
 
2449
        cert_list = (gnutls.certificate_get_peers
 
1862
2450
                     (session._c_object, ctypes.byref(list_size)))
 
1863
2451
        if not bool(cert_list) and list_size.value != 0:
 
1864
 
            raise gnutls.errors.GNUTLSError("error getting peer"
 
 
2452
            raise gnutls.Error("error getting peer certificate")
 
1866
2453
        if list_size.value == 0:
 
1868
2455
        cert = cert_list[0]
 
1869
2456
        return ctypes.string_at(cert.data, cert.size)
 
 
2459
    def key_id(certificate):
 
 
2460
        "Convert a certificate bytestring to a hexdigit key ID"
 
 
2461
        # New GnuTLS "datum" with the public key
 
 
2462
        datum = gnutls.datum_t(
 
 
2463
            ctypes.cast(ctypes.c_char_p(certificate),
 
 
2464
                        ctypes.POINTER(ctypes.c_ubyte)),
 
 
2465
            ctypes.c_uint(len(certificate)))
 
 
2466
        # XXX all these need to be created in the gnutls "module"
 
 
2467
        # New empty GnuTLS certificate
 
 
2468
        pubkey = gnutls.pubkey_t()
 
 
2469
        gnutls.pubkey_init(ctypes.byref(pubkey))
 
 
2470
        # Import the raw public key into the certificate
 
 
2471
        gnutls.pubkey_import(pubkey,
 
 
2472
                             ctypes.byref(datum),
 
 
2473
                             gnutls.X509_FMT_DER)
 
 
2474
        # New buffer for the key ID
 
 
2475
        buf = ctypes.create_string_buffer(32)
 
 
2476
        buf_len = ctypes.c_size_t(len(buf))
 
 
2477
        # Get the key ID from the raw public key into the buffer
 
 
2478
        gnutls.pubkey_get_key_id(
 
 
2480
            gnutls.KEYID_USE_SHA256,
 
 
2481
            ctypes.cast(ctypes.byref(buf),
 
 
2482
                        ctypes.POINTER(ctypes.c_ubyte)),
 
 
2483
            ctypes.byref(buf_len))
 
 
2484
        # Deinit the certificate
 
 
2485
        gnutls.pubkey_deinit(pubkey)
 
 
2487
        # Convert the buffer to a Python bytestring
 
 
2488
        key_id = ctypes.string_at(buf, buf_len.value)
 
 
2489
        # Convert the bytestring to hexadecimal notation
 
 
2490
        hex_key_id = binascii.hexlify(key_id).upper()
 
1872
2494
    def fingerprint(openpgp):
 
1873
2495
        "Convert an OpenPGP bytestring to a hexdigit fingerprint"
 
1874
2496
        # New GnuTLS "datum" with the OpenPGP public key
 
1875
 
        datum = gnutls.library.types.gnutls_datum_t(
 
 
2497
        datum = gnutls.datum_t(
 
1876
2498
            ctypes.cast(ctypes.c_char_p(openpgp),
 
1877
2499
                        ctypes.POINTER(ctypes.c_ubyte)),
 
1878
2500
            ctypes.c_uint(len(openpgp)))
 
1879
2501
        # New empty GnuTLS certificate
 
1880
 
        crt = gnutls.library.types.gnutls_openpgp_crt_t()
 
1881
 
        gnutls.library.functions.gnutls_openpgp_crt_init(
 
 
2502
        crt = gnutls.openpgp_crt_t()
 
 
2503
        gnutls.openpgp_crt_init(ctypes.byref(crt))
 
1883
2504
        # Import the OpenPGP public key into the certificate
 
1884
 
        gnutls.library.functions.gnutls_openpgp_crt_import(
 
1885
 
            crt, ctypes.byref(datum),
 
1886
 
            gnutls.library.constants.GNUTLS_OPENPGP_FMT_RAW)
 
 
2505
        gnutls.openpgp_crt_import(crt, ctypes.byref(datum),
 
 
2506
                                  gnutls.OPENPGP_FMT_RAW)
 
1887
2507
        # Verify the self signature in the key
 
1888
2508
        crtverify = ctypes.c_uint()
 
1889
 
        gnutls.library.functions.gnutls_openpgp_crt_verify_self(
 
1890
 
            crt, 0, ctypes.byref(crtverify))
 
 
2509
        gnutls.openpgp_crt_verify_self(crt, 0,
 
 
2510
                                       ctypes.byref(crtverify))
 
1891
2511
        if crtverify.value != 0:
 
1892
 
            gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
 
1893
 
            raise gnutls.errors.CertificateSecurityError(
 
 
2512
            gnutls.openpgp_crt_deinit(crt)
 
 
2513
            raise gnutls.CertificateSecurityError(code
 
1895
2515
        # New buffer for the fingerprint
 
1896
2516
        buf = ctypes.create_string_buffer(20)
 
1897
2517
        buf_len = ctypes.c_size_t()
 
1898
2518
        # Get the fingerprint from the certificate into the buffer
 
1899
 
        gnutls.library.functions.gnutls_openpgp_crt_get_fingerprint(
 
1900
 
            crt, ctypes.byref(buf), ctypes.byref(buf_len))
 
 
2519
        gnutls.openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
 
 
2520
                                           ctypes.byref(buf_len))
 
1901
2521
        # Deinit the certificate
 
1902
 
        gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
 
 
2522
        gnutls.openpgp_crt_deinit(crt)
 
1903
2523
        # Convert the buffer to a Python bytestring
 
1904
2524
        fpr = ctypes.string_at(buf, buf_len.value)
 
1905
2525
        # Convert the bytestring to hexadecimal notation
 
 
1993
2614
        # socket_wrapper(), if socketfd was set.
 
1994
2615
        socketserver.TCPServer.__init__(self, server_address,
 
1995
2616
                                        RequestHandlerClass)
 
1997
2618
    def server_bind(self):
 
1998
2619
        """This overrides the normal server_bind() function
 
1999
2620
        to bind to an interface if one was specified, and also NOT to
 
2000
2621
        bind to an address or port if they were not specified."""
 
 
2622
        global SO_BINDTODEVICE
 
2001
2623
        if self.interface is not None:
 
2002
2624
            if SO_BINDTODEVICE is None:
 
2003
 
                logger.error("SO_BINDTODEVICE does not exist;"
 
2004
 
                             " cannot bind to interface %s",
 
2008
 
                    self.socket.setsockopt(
 
2009
 
                        socket.SOL_SOCKET, SO_BINDTODEVICE,
 
2010
 
                        (self.interface + "\0").encode("utf-8"))
 
2011
 
                except socket.error as error:
 
2012
 
                    if error.errno == errno.EPERM:
 
2013
 
                        logger.error("No permission to bind to"
 
2014
 
                                     " interface %s", self.interface)
 
2015
 
                    elif error.errno == errno.ENOPROTOOPT:
 
2016
 
                        logger.error("SO_BINDTODEVICE not available;"
 
2017
 
                                     " cannot bind to interface %s",
 
2019
 
                    elif error.errno == errno.ENODEV:
 
2020
 
                        logger.error("Interface %s does not exist,"
 
2021
 
                                     " cannot bind", self.interface)
 
 
2625
                # Fall back to a hard-coded value which seems to be
 
 
2627
                logger.warning("SO_BINDTODEVICE not found, trying 25")
 
 
2628
                SO_BINDTODEVICE = 25
 
 
2630
                self.socket.setsockopt(
 
 
2631
                    socket.SOL_SOCKET, SO_BINDTODEVICE,
 
 
2632
                    (self.interface + "\0").encode("utf-8"))
 
 
2633
            except socket.error as error:
 
 
2634
                if error.errno == errno.EPERM:
 
 
2635
                    logger.error("No permission to bind to"
 
 
2636
                                 " interface %s", self.interface)
 
 
2637
                elif error.errno == errno.ENOPROTOOPT:
 
 
2638
                    logger.error("SO_BINDTODEVICE not available;"
 
 
2639
                                 " cannot bind to interface %s",
 
 
2641
                elif error.errno == errno.ENODEV:
 
 
2642
                    logger.error("Interface %s does not exist,"
 
 
2643
                                 " cannot bind", self.interface)
 
2024
2646
        # Only bind(2) the socket if we really need to.
 
2025
2647
        if self.server_address[0] or self.server_address[1]:
 
 
2648
            if self.server_address[1]:
 
 
2649
                self.allow_reuse_address = True
 
2026
2650
            if not self.server_address[0]:
 
2027
2651
                if self.address_family == socket.AF_INET6:
 
2028
 
                    any_address = "::" # in6addr_any
 
 
2652
                    any_address = "::"  # in6addr_any
 
2030
 
                    any_address = "0.0.0.0" # INADDR_ANY
 
 
2654
                    any_address = "0.0.0.0"  # INADDR_ANY
 
2031
2655
                self.server_address = (any_address,
 
2032
2656
                                       self.server_address[1])
 
2033
2657
            elif not self.server_address[1]:
 
 
2067
2691
        self.gnutls_priority = gnutls_priority
 
2068
2692
        IPv6_TCPServer.__init__(self, server_address,
 
2069
2693
                                RequestHandlerClass,
 
2070
 
                                interface = interface,
 
2071
 
                                use_ipv6 = use_ipv6,
 
2072
 
                                socketfd = socketfd)
 
 
2694
                                interface=interface,
 
2074
2698
    def server_activate(self):
 
2075
2699
        if self.enabled:
 
2076
2700
            return socketserver.TCPServer.server_activate(self)
 
2078
2702
    def enable(self):
 
2079
2703
        self.enabled = True
 
2081
2705
    def add_pipe(self, parent_pipe, proc):
 
2082
2706
        # Call "handle_ipc" for both data and EOF events
 
2083
 
        gobject.io_add_watch(
 
2084
 
            parent_pipe.fileno(),
 
2085
 
            gobject.IO_IN | gobject.IO_HUP,
 
 
2708
            GLib.IOChannel.unix_new(parent_pipe.fileno()),
 
 
2709
            GLib.PRIORITY_DEFAULT, GLib.IO_IN | GLib.IO_HUP,
 
2086
2710
            functools.partial(self.handle_ipc,
 
2087
 
                              parent_pipe = parent_pipe,
 
 
2711
                              parent_pipe=parent_pipe,
 
2090
2714
    def handle_ipc(self, source, condition,
 
2091
2715
                   parent_pipe=None,
 
2093
2717
                   client_object=None):
 
2094
2718
        # error, or the other end of multiprocessing.Pipe has closed
 
2095
 
        if condition & (gobject.IO_ERR | gobject.IO_HUP):
 
 
2719
        if condition & (GLib.IO_ERR | GLib.IO_HUP):
 
2096
2720
            # Wait for other process to exit
 
2100
2724
        # Read a request from the child
 
2101
2725
        request = parent_pipe.recv()
 
2102
2726
        command = request[0]
 
2104
2728
        if command == 'init':
 
2106
 
            address = request[2]
 
2108
 
            for c in self.clients.itervalues():
 
2109
 
                if c.fingerprint == fpr:
 
 
2729
            key_id = request[1].decode("ascii")
 
 
2730
            fpr = request[2].decode("ascii")
 
 
2731
            address = request[3]
 
 
2733
            for c in self.clients.values():
 
 
2734
                if key_id == ("E3B0C44298FC1C149AFBF4C8996FB924"
 
 
2735
                              "27AE41E4649B934CA495991B7852B855"):
 
 
2737
                if key_id and c.key_id == key_id:
 
 
2740
                if fpr and c.fingerprint == fpr:
 
2113
 
                logger.info("Client not found for fingerprint: %s, ad"
 
2114
 
                            "dress: %s", fpr, address)
 
 
2744
                logger.info("Client not found for key ID: %s, address"
 
 
2745
                            ": %s", key_id or fpr, address)
 
2115
2746
                if self.use_dbus:
 
2116
2747
                    # Emit D-Bus signal
 
2117
 
                    mandos_dbus_service.ClientNotFound(fpr,
 
 
2748
                    mandos_dbus_service.ClientNotFound(key_id or fpr,
 
2119
2750
                parent_pipe.send(False)
 
2122
 
            gobject.io_add_watch(
 
2123
 
                parent_pipe.fileno(),
 
2124
 
                gobject.IO_IN | gobject.IO_HUP,
 
 
2754
                GLib.IOChannel.unix_new(parent_pipe.fileno()),
 
 
2755
                GLib.PRIORITY_DEFAULT, GLib.IO_IN | GLib.IO_HUP,
 
2125
2756
                functools.partial(self.handle_ipc,
 
2126
 
                                  parent_pipe = parent_pipe,
 
2128
 
                                  client_object = client))
 
 
2757
                                  parent_pipe=parent_pipe,
 
 
2759
                                  client_object=client))
 
2129
2760
            parent_pipe.send(True)
 
2130
2761
            # remove the old hook in favor of the new above hook on
 
 
2578
3221
        protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
 
2579
3222
        service = AvahiServiceToSyslog(
 
2580
 
            name = server_settings["servicename"],
 
2581
 
            servicetype = "_mandos._tcp",
 
2582
 
            protocol = protocol,
 
 
3223
            name=server_settings["servicename"],
 
 
3224
            servicetype="_mandos._tcp",
 
2584
3227
        if server_settings["interface"]:
 
2585
3228
            service.interface = if_nametoindex(
 
2586
3229
                server_settings["interface"].encode("utf-8"))
 
2588
3231
    global multiprocessing_manager
 
2589
3232
    multiprocessing_manager = multiprocessing.Manager()
 
2591
3234
    client_class = Client
 
2593
 
        client_class = functools.partial(ClientDBus, bus = bus)
 
 
3236
        client_class = functools.partial(ClientDBus, bus=bus)
 
2595
3238
    client_settings = Client.config_parser(client_config)
 
2596
3239
    old_client_settings = {}
 
2597
3240
    clients_data = {}
 
2599
3242
    # This is used to redirect stdout and stderr for checker processes
 
2601
 
    wnull = open(os.devnull, "w") # A writable /dev/null
 
 
3244
    wnull = open(os.devnull, "w")  # A writable /dev/null
 
2602
3245
    # Only used if server is running in foreground but not in debug
 
2604
3247
    if debug or not foreground:
 
2607
3250
    # Get client data and settings from last running state.
 
2608
3251
    if server_settings["restore"]:
 
2610
3253
            with open(stored_state_path, "rb") as stored_state:
 
2611
 
                clients_data, old_client_settings = pickle.load(
 
 
3254
                if sys.version_info.major == 2:
 
 
3255
                    clients_data, old_client_settings = pickle.load(
 
 
3258
                    bytes_clients_data, bytes_old_client_settings = (
 
 
3259
                        pickle.load(stored_state, encoding="bytes"))
 
 
3260
                    #   Fix bytes to strings
 
 
3263
                    clients_data = {(key.decode("utf-8")
 
 
3264
                                     if isinstance(key, bytes)
 
 
3267
                                    bytes_clients_data.items()}
 
 
3268
                    del bytes_clients_data
 
 
3269
                    for key in clients_data:
 
 
3270
                        value = {(k.decode("utf-8")
 
 
3271
                                  if isinstance(k, bytes) else k): v
 
 
3273
                                 clients_data[key].items()}
 
 
3274
                        clients_data[key] = value
 
 
3276
                        value["client_structure"] = [
 
 
3278
                             if isinstance(s, bytes)
 
 
3280
                            value["client_structure"]]
 
 
3281
                        # .name, .host, and .checker_command
 
 
3282
                        for k in ("name", "host", "checker_command"):
 
 
3283
                            if isinstance(value[k], bytes):
 
 
3284
                                value[k] = value[k].decode("utf-8")
 
 
3285
                        if "key_id" not in value:
 
 
3286
                            value["key_id"] = ""
 
 
3287
                        elif "fingerprint" not in value:
 
 
3288
                            value["fingerprint"] = ""
 
 
3289
                    #  old_client_settings
 
 
3291
                    old_client_settings = {
 
 
3292
                        (key.decode("utf-8")
 
 
3293
                         if isinstance(key, bytes)
 
 
3296
                        bytes_old_client_settings.items()}
 
 
3297
                    del bytes_old_client_settings
 
 
3298
                    # .host and .checker_command
 
 
3299
                    for value in old_client_settings.values():
 
 
3300
                        for attribute in ("host", "checker_command"):
 
 
3301
                            if isinstance(value[attribute], bytes):
 
 
3302
                                value[attribute] = (value[attribute]
 
2613
3304
            os.remove(stored_state_path)
 
2614
3305
        except IOError as e:
 
2615
3306
            if e.errno == errno.ENOENT:
 
 
2715
3406
                             pidfilename, pid)
 
2717
3408
        del pidfilename
 
2719
 
    signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
 
2720
 
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
 
 
3410
    for termsig in (signal.SIGHUP, signal.SIGTERM):
 
 
3411
        GLib.unix_signal_add(GLib.PRIORITY_HIGH, termsig,
 
 
3412
                             lambda: main_loop.quit() and False)
 
2724
3416
        @alternate_dbus_interfaces(
 
2725
 
            { "se.recompile.Mandos": "se.bsnet.fukt.Mandos" })
 
2726
 
        class MandosDBusService(DBusObjectWithProperties):
 
 
3417
            {"se.recompile.Mandos": "se.bsnet.fukt.Mandos"})
 
 
3418
        class MandosDBusService(DBusObjectWithObjectManager):
 
2727
3419
            """A D-Bus proxy object"""
 
2729
3421
            def __init__(self):
 
2730
3422
                dbus.service.Object.__init__(self, bus, "/")
 
2732
3424
            _interface = "se.recompile.Mandos"
 
2734
 
            @dbus_interface_annotations(_interface)
 
2737
 
                    "org.freedesktop.DBus.Property.EmitsChangedSignal":
 
2740
3426
            @dbus.service.signal(_interface, signature="o")
 
2741
3427
            def ClientAdded(self, objpath):
 
2745
3431
            @dbus.service.signal(_interface, signature="ss")
 
2746
 
            def ClientNotFound(self, fingerprint, address):
 
 
3432
            def ClientNotFound(self, key_id, address):
 
 
3436
            @dbus_annotations({"org.freedesktop.DBus.Deprecated":
 
2750
3438
            @dbus.service.signal(_interface, signature="os")
 
2751
3439
            def ClientRemoved(self, objpath, name):
 
 
3443
            @dbus_annotations({"org.freedesktop.DBus.Deprecated":
 
2755
3445
            @dbus.service.method(_interface, out_signature="ao")
 
2756
3446
            def GetAllClients(self):
 
2758
3448
                return dbus.Array(c.dbus_object_path for c in
 
2759
 
                                  tcp_server.clients.itervalues())
 
 
3449
                                  tcp_server.clients.values())
 
 
3451
            @dbus_annotations({"org.freedesktop.DBus.Deprecated":
 
2761
3453
            @dbus.service.method(_interface,
 
2762
3454
                                 out_signature="a{oa{sv}}")
 
2763
3455
            def GetAllClientsWithProperties(self):
 
2765
3457
                return dbus.Dictionary(
 
2766
 
                    { c.dbus_object_path: c.GetAll("")
 
2767
 
                      for c in tcp_server.clients.itervalues() },
 
 
3458
                    {c.dbus_object_path: c.GetAll(
 
 
3459
                        "se.recompile.Mandos.Client")
 
 
3460
                     for c in tcp_server.clients.values()},
 
2768
3461
                    signature="oa{sv}")
 
2770
3463
            @dbus.service.method(_interface, in_signature="o")
 
2771
3464
            def RemoveClient(self, object_path):
 
2773
 
                for c in tcp_server.clients.itervalues():
 
 
3466
                for c in tcp_server.clients.values():
 
2774
3467
                    if c.dbus_object_path == object_path:
 
2775
3468
                        del tcp_server.clients[c.name]
 
2776
3469
                        c.remove_from_connection()
 
2777
 
                        # Don't signal anything except ClientRemoved
 
 
3470
                        # Don't signal the disabling
 
2778
3471
                        c.disable(quiet=True)
 
2780
 
                        self.ClientRemoved(object_path, c.name)
 
 
3472
                        # Emit D-Bus signal for removal
 
 
3473
                        self.client_removed_signal(c)
 
2782
3475
                raise KeyError(object_path)
 
 
3479
            @dbus.service.method(dbus.OBJECT_MANAGER_IFACE,
 
 
3480
                                 out_signature="a{oa{sa{sv}}}")
 
 
3481
            def GetManagedObjects(self):
 
 
3483
                return dbus.Dictionary(
 
 
3484
                    {client.dbus_object_path:
 
 
3486
                         {interface: client.GetAll(interface)
 
 
3488
                          client._get_all_interface_names()})
 
 
3489
                     for client in tcp_server.clients.values()})
 
 
3491
            def client_added_signal(self, client):
 
 
3492
                """Send the new standard signal and the old signal"""
 
 
3494
                    # New standard signal
 
 
3495
                    self.InterfacesAdded(
 
 
3496
                        client.dbus_object_path,
 
 
3498
                            {interface: client.GetAll(interface)
 
 
3500
                             client._get_all_interface_names()}))
 
 
3502
                    self.ClientAdded(client.dbus_object_path)
 
 
3504
            def client_removed_signal(self, client):
 
 
3505
                """Send the new standard signal and the old signal"""
 
 
3507
                    # New standard signal
 
 
3508
                    self.InterfacesRemoved(
 
 
3509
                        client.dbus_object_path,
 
 
3510
                        client._get_all_interface_names())
 
 
3512
                    self.ClientRemoved(client.dbus_object_path,
 
2786
3515
        mandos_dbus_service = MandosDBusService()
 
 
3517
    # Save modules to variables to exempt the modules from being
 
 
3518
    # unloaded before the function registered with atexit() is run.
 
 
3519
    mp = multiprocessing
 
2789
3523
        "Cleanup function; run on exit"
 
2791
3525
            service.cleanup()
 
2793
 
        multiprocessing.active_children()
 
 
3527
        mp.active_children()
 
2795
3529
        if not (tcp_server.clients or client_settings):
 
2798
3532
        # Store client before exiting. Secrets are encrypted with key
 
2799
3533
        # based on what config file has. If config file is
 
2800
3534
        # removed/edited, old secret will thus be unrecovable.
 
2802
3536
        with PGPEngine() as pgp:
 
2803
 
            for client in tcp_server.clients.itervalues():
 
 
3537
            for client in tcp_server.clients.values():
 
2804
3538
                key = client_settings[client.name]["secret"]
 
2805
3539
                client.encrypted_secret = pgp.encrypt(client.secret,
 
2807
3541
                client_dict = {}
 
2809
3543
                # A list of attributes that can not be pickled
 
2811
 
                exclude = { "bus", "changedstate", "secret",
 
2812
 
                            "checker", "server_settings" }
 
 
3545
                exclude = {"bus", "changedstate", "secret",
 
 
3546
                           "checker", "server_settings"}
 
2813
3547
                for name, typ in inspect.getmembers(dbus.service
 
2815
3549
                    exclude.add(name)
 
2817
3551
                client_dict["encrypted_secret"] = (client
 
2818
3552
                                                   .encrypted_secret)
 
2819
3553
                for attr in client.client_structure:
 
2820
3554
                    if attr not in exclude:
 
2821
3555
                        client_dict[attr] = getattr(client, attr)
 
2823
3557
                clients[client.name] = client_dict
 
2824
3558
                del client_settings[client.name]["secret"]
 
2827
3561
            with tempfile.NamedTemporaryFile(