/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos

  • Committer: Teddy Hogeborn
  • Date: 2010-06-19 00:37:04 UTC
  • mto: (24.1.149 mandos)
  • mto: This revision was merged to the branch mainline in revision 417.
  • Revision ID: teddy@fukt.bsnet.se-20100619003704-vpicvssvv1ktg2om
* mandos (ClientHandler.handle): Set up the GnuTLS session object
                                 before reading the protocol number.
 (ClientHandler.handle/ProxyObject): New.

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
import logging
56
56
import logging.handlers
57
57
import pwd
58
 
from contextlib import closing
 
58
import contextlib
59
59
import struct
60
60
import fcntl
61
61
import functools
 
62
import cPickle as pickle
 
63
import select
62
64
 
63
65
import dbus
64
66
import dbus.service
242
244
    enabled:    bool()
243
245
    last_checked_ok: datetime.datetime(); (UTC) or None
244
246
    timeout:    datetime.timedelta(); How long from last_checked_ok
245
 
                                      until this client is invalid
 
247
                                      until this client is disabled
246
248
    interval:   datetime.timedelta(); How often to start a new checker
247
249
    disable_hook:  If set, called by disable() as disable_hook(self)
248
250
    checker:    subprocess.Popen(); a running checker process used
290
292
        if u"secret" in config:
291
293
            self.secret = config[u"secret"].decode(u"base64")
292
294
        elif u"secfile" in config:
293
 
            with closing(open(os.path.expanduser
294
 
                              (os.path.expandvars
295
 
                               (config[u"secfile"])),
296
 
                              "rb")) as secfile:
 
295
            with open(os.path.expanduser(os.path.expandvars
 
296
                                         (config[u"secfile"])),
 
297
                      "rb") as secfile:
297
298
                self.secret = secfile.read()
298
299
        else:
299
300
            raise TypeError(u"No secret or secfile for client %s"
325
326
        self.checker_initiator_tag = (gobject.timeout_add
326
327
                                      (self.interval_milliseconds(),
327
328
                                       self.start_checker))
328
 
        # Also start a new checker *right now*.
329
 
        self.start_checker()
330
329
        # Schedule a disable() when 'timeout' has passed
331
330
        self.disable_initiator_tag = (gobject.timeout_add
332
331
                                   (self.timeout_milliseconds(),
333
332
                                    self.disable))
334
333
        self.enabled = True
 
334
        # Also start a new checker *right now*.
 
335
        self.start_checker()
335
336
    
336
 
    def disable(self):
 
337
    def disable(self, quiet=True):
337
338
        """Disable this client."""
338
339
        if not getattr(self, "enabled", False):
339
340
            return False
340
 
        logger.info(u"Disabling client %s", self.name)
 
341
        if not quiet:
 
342
            logger.info(u"Disabling client %s", self.name)
341
343
        if getattr(self, u"disable_initiator_tag", False):
342
344
            gobject.source_remove(self.disable_initiator_tag)
343
345
            self.disable_initiator_tag = None
395
397
        # client would inevitably timeout, since no checker would get
396
398
        # a chance to run to completion.  If we instead leave running
397
399
        # checkers alone, the checker would have to take more time
398
 
        # than 'timeout' for the client to be declared invalid, which
399
 
        # is as it should be.
 
400
        # than 'timeout' for the client to be disabled, which is as it
 
401
        # should be.
400
402
        
401
403
        # If a checker exists, make sure it is not a zombie
402
404
        try:
467
469
        logger.debug(u"Stopping checker for %(name)s", vars(self))
468
470
        try:
469
471
            os.kill(self.checker.pid, signal.SIGTERM)
470
 
            #os.sleep(0.5)
 
472
            #time.sleep(0.5)
471
473
            #if self.checker.poll() is None:
472
474
            #    os.kill(self.checker.pid, signal.SIGKILL)
473
475
        except OSError, error:
474
476
            if error.errno != errno.ESRCH: # No such process
475
477
                raise
476
478
        self.checker = None
477
 
    
478
 
    def still_valid(self):
479
 
        """Has the timeout not yet passed for this client?"""
480
 
        if not getattr(self, u"enabled", False):
481
 
            return False
482
 
        now = datetime.datetime.utcnow()
483
 
        if self.last_checked_ok is None:
484
 
            return now < (self.created + self.timeout)
485
 
        else:
486
 
            return now < (self.last_checked_ok + self.timeout)
487
479
 
488
480
 
489
481
def dbus_service_property(dbus_interface, signature=u"v",
498
490
    dbus.service.method, except there is only "signature", since the
499
491
    type from Get() and the type sent to Set() is the same.
500
492
    """
 
493
    # Encoding deeply encoded byte arrays is not supported yet by the
 
494
    # "Set" method, so we fail early here:
 
495
    if byte_arrays and signature != u"ay":
 
496
        raise ValueError(u"Byte arrays not supported for non-'ay'"
 
497
                         u" signature %r" % signature)
501
498
    def decorator(func):
502
499
        func._dbus_is_property = True
503
500
        func._dbus_interface = dbus_interface
589
586
        if prop._dbus_access == u"read":
590
587
            raise DBusPropertyAccessException(property_name)
591
588
        if prop._dbus_get_args_options[u"byte_arrays"]:
 
589
            # The byte_arrays option is not supported yet on
 
590
            # signatures other than "ay".
 
591
            if prop._dbus_signature != u"ay":
 
592
                raise ValueError
592
593
            value = dbus.ByteArray(''.join(unichr(byte)
593
594
                                           for byte in value))
594
595
        prop(value)
705
706
                                       variant_level=1))
706
707
        return r
707
708
    
708
 
    def disable(self, signal = True):
 
709
    def disable(self, quiet = False):
709
710
        oldstate = getattr(self, u"enabled", False)
710
 
        r = Client.disable(self)
711
 
        if signal and oldstate != self.enabled:
 
711
        r = Client.disable(self, quiet=quiet)
 
712
        if not quiet and oldstate != self.enabled:
712
713
            # Emit D-Bus signal
713
714
            self.PropertyChanged(dbus.String(u"enabled"),
714
715
                                 dbus.Boolean(False, variant_level=1))
780
781
                                 dbus.Boolean(False, variant_level=1))
781
782
        return r
782
783
    
783
 
    ## D-Bus methods & signals
 
784
    ## D-Bus methods, signals & properties
784
785
    _interface = u"se.bsnet.fukt.Mandos.Client"
785
786
    
786
 
    # CheckedOK - method
787
 
    @dbus.service.method(_interface)
788
 
    def CheckedOK(self):
789
 
        return self.checked_ok()
 
787
    ## Signals
790
788
    
791
789
    # CheckerCompleted - signal
792
790
    @dbus.service.signal(_interface, signature=u"nxs")
818
816
        "D-Bus signal"
819
817
        pass
820
818
    
 
819
    ## Methods
 
820
    
 
821
    # CheckedOK - method
 
822
    @dbus.service.method(_interface)
 
823
    def CheckedOK(self):
 
824
        return self.checked_ok()
 
825
    
821
826
    # Enable - method
822
827
    @dbus.service.method(_interface)
823
828
    def Enable(self):
841
846
    def StopChecker(self):
842
847
        self.stop_checker()
843
848
    
 
849
    ## Properties
 
850
    
844
851
    # name - property
845
852
    @dbus_service_property(_interface, signature=u"s", access=u"read")
846
853
    def name_dbus_property(self):
989
996
    def handle(self):
990
997
        logger.info(u"TCP connection from: %s",
991
998
                    unicode(self.client_address))
992
 
        logger.debug(u"IPC Pipe FD: %d", self.server.pipe[1])
 
999
        logger.debug(u"IPC Pipe FD: %d",
 
1000
                     self.server.child_pipe[1].fileno())
993
1001
        # Open IPC pipe to parent process
994
 
        with closing(os.fdopen(self.server.pipe[1], u"w", 1)) as ipc:
 
1002
        with contextlib.nested(self.server.child_pipe[1],
 
1003
                               self.server.parent_pipe[0]
 
1004
                               ) as (ipc, ipc_return):
995
1005
            session = (gnutls.connection
996
1006
                       .ClientSession(self.request,
997
1007
                                      gnutls.connection
998
1008
                                      .X509Credentials()))
999
1009
            
1000
 
            line = self.request.makefile().readline()
1001
 
            logger.debug(u"Protocol version: %r", line)
1002
 
            try:
1003
 
                if int(line.strip().split()[0]) > 1:
1004
 
                    raise RuntimeError
1005
 
            except (ValueError, IndexError, RuntimeError), error:
1006
 
                logger.error(u"Unknown protocol version: %s", error)
1007
 
                return
1008
 
            
1009
1010
            # Note: gnutls.connection.X509Credentials is really a
1010
1011
            # generic GnuTLS certificate credentials object so long as
1011
1012
            # no X.509 keys are added to it.  Therefore, we can use it
1023
1024
             .gnutls_priority_set_direct(session._c_object,
1024
1025
                                         priority, None))
1025
1026
            
 
1027
            # Start communication using the Mandos protocol
 
1028
            # Get protocol number
 
1029
            line = self.request.makefile().readline()
 
1030
            logger.debug(u"Protocol version: %r", line)
 
1031
            try:
 
1032
                if int(line.strip().split()[0]) > 1:
 
1033
                    raise RuntimeError
 
1034
            except (ValueError, IndexError, RuntimeError), error:
 
1035
                logger.error(u"Unknown protocol version: %s", error)
 
1036
                return
 
1037
            
 
1038
            # Start GnuTLS connection
1026
1039
            try:
1027
1040
                session.handshake()
1028
1041
            except gnutls.errors.GNUTLSError, error:
1032
1045
                return
1033
1046
            logger.debug(u"Handshake succeeded")
1034
1047
            try:
1035
 
                fpr = self.fingerprint(self.peer_certificate(session))
1036
 
            except (TypeError, gnutls.errors.GNUTLSError), error:
1037
 
                logger.warning(u"Bad certificate: %s", error)
1038
 
                session.bye()
1039
 
                return
1040
 
            logger.debug(u"Fingerprint: %s", fpr)
1041
 
            
1042
 
            for c in self.server.clients:
1043
 
                if c.fingerprint == fpr:
1044
 
                    client = c
1045
 
                    break
1046
 
            else:
1047
 
                ipc.write(u"NOTFOUND %s %s\n"
1048
 
                          % (fpr, unicode(self.client_address)))
1049
 
                session.bye()
1050
 
                return
1051
 
            # Have to check if client.still_valid(), since it is
1052
 
            # possible that the client timed out while establishing
1053
 
            # the GnuTLS session.
1054
 
            if not client.still_valid():
1055
 
                ipc.write(u"INVALID %s\n" % client.name)
1056
 
                session.bye()
1057
 
                return
1058
 
            ipc.write(u"SENDING %s\n" % client.name)
1059
 
            sent_size = 0
1060
 
            while sent_size < len(client.secret):
1061
 
                sent = session.send(client.secret[sent_size:])
1062
 
                logger.debug(u"Sent: %d, remaining: %d",
1063
 
                             sent, len(client.secret)
1064
 
                             - (sent_size + sent))
1065
 
                sent_size += sent
1066
 
            session.bye()
 
1048
                try:
 
1049
                    fpr = self.fingerprint(self.peer_certificate
 
1050
                                           (session))
 
1051
                except (TypeError, gnutls.errors.GNUTLSError), error:
 
1052
                    logger.warning(u"Bad certificate: %s", error)
 
1053
                    return
 
1054
                logger.debug(u"Fingerprint: %s", fpr)
 
1055
 
 
1056
                for c in self.server.clients:
 
1057
                    if c.fingerprint == fpr:
 
1058
                        client = c
 
1059
                        break
 
1060
                else:
 
1061
                    ipc.write(u"NOTFOUND %s %s\n"
 
1062
                              % (fpr, unicode(self.client_address)))
 
1063
                    return
 
1064
                
 
1065
                class ClientProxy(object):
 
1066
                    """Client proxy object.  Not for calling methods."""
 
1067
                    def __init__(self, client):
 
1068
                        self.client = client
 
1069
                    def __getattr__(self, name):
 
1070
                        if name.startswith("ipc_"):
 
1071
                            def tempfunc():
 
1072
                                ipc.write("%s %s\n" % (name[4:].upper(),
 
1073
                                                       self.client.name))
 
1074
                            return tempfunc
 
1075
                        if not hasattr(self.client, name):
 
1076
                            raise AttributeError
 
1077
                        ipc.write(u"GETATTR %s %s\n"
 
1078
                                  % (name, self.client.fingerprint))
 
1079
                        return pickle.load(ipc_return)
 
1080
                clientproxy = ClientProxy(client)
 
1081
                # Have to check if client.enabled, since it is
 
1082
                # possible that the client was disabled since the
 
1083
                # GnuTLS session was established.
 
1084
                if not clientproxy.enabled:
 
1085
                    clientproxy.ipc_disabled()
 
1086
                    return
 
1087
                
 
1088
                clientproxy.ipc_sending()
 
1089
                sent_size = 0
 
1090
                while sent_size < len(client.secret):
 
1091
                    sent = session.send(client.secret[sent_size:])
 
1092
                    logger.debug(u"Sent: %d, remaining: %d",
 
1093
                                 sent, len(client.secret)
 
1094
                                 - (sent_size + sent))
 
1095
                    sent_size += sent
 
1096
            finally:
 
1097
                session.bye()
1067
1098
    
1068
1099
    @staticmethod
1069
1100
    def peer_certificate(session):
1129
1160
        return hex_fpr
1130
1161
 
1131
1162
 
1132
 
class ForkingMixInWithPipe(socketserver.ForkingMixIn, object):
1133
 
    """Like socketserver.ForkingMixIn, but also pass a pipe."""
 
1163
class ForkingMixInWithPipes(socketserver.ForkingMixIn, object):
 
1164
    """Like socketserver.ForkingMixIn, but also pass a pipe pair."""
1134
1165
    def process_request(self, request, client_address):
1135
1166
        """Overrides and wraps the original process_request().
1136
1167
        
1137
1168
        This function creates a new pipe in self.pipe
1138
1169
        """
1139
 
        self.pipe = os.pipe()
1140
 
        super(ForkingMixInWithPipe,
 
1170
        # Child writes to child_pipe
 
1171
        self.child_pipe = map(os.fdopen, os.pipe(), u"rw", (1, 0))
 
1172
        # Parent writes to parent_pipe
 
1173
        self.parent_pipe = map(os.fdopen, os.pipe(), u"rw", (1, 0))
 
1174
        super(ForkingMixInWithPipes,
1141
1175
              self).process_request(request, client_address)
1142
 
        os.close(self.pipe[1])  # close write end
1143
 
        self.add_pipe(self.pipe[0])
1144
 
    def add_pipe(self, pipe):
 
1176
        # Close unused ends for parent
 
1177
        self.parent_pipe[0].close() # close read end
 
1178
        self.child_pipe[1].close()  # close write end
 
1179
        self.add_pipe_fds(self.child_pipe[0], self.parent_pipe[1])
 
1180
    def add_pipe_fds(self, child_pipe_fd, parent_pipe_fd):
1145
1181
        """Dummy function; override as necessary"""
1146
 
        os.close(pipe)
1147
 
 
1148
 
 
1149
 
class IPv6_TCPServer(ForkingMixInWithPipe,
 
1182
        child_pipe_fd.close()
 
1183
        parent_pipe_fd.close()
 
1184
 
 
1185
 
 
1186
class IPv6_TCPServer(ForkingMixInWithPipes,
1150
1187
                     socketserver.TCPServer, object):
1151
1188
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
1152
1189
    
1237
1274
            return socketserver.TCPServer.server_activate(self)
1238
1275
    def enable(self):
1239
1276
        self.enabled = True
1240
 
    def add_pipe(self, pipe):
 
1277
    def add_pipe_fds(self, child_pipe_fd, parent_pipe_fd):
1241
1278
        # Call "handle_ipc" for both data and EOF events
1242
 
        gobject.io_add_watch(pipe, gobject.IO_IN | gobject.IO_HUP,
1243
 
                             self.handle_ipc)
1244
 
    def handle_ipc(self, source, condition, file_objects={}):
 
1279
        gobject.io_add_watch(child_pipe_fd.fileno(),
 
1280
                             gobject.IO_IN | gobject.IO_HUP,
 
1281
                             functools.partial(self.handle_ipc,
 
1282
                                               reply = parent_pipe_fd,
 
1283
                                               sender= child_pipe_fd))
 
1284
    def handle_ipc(self, source, condition, reply=None, sender=None):
1245
1285
        condition_names = {
1246
1286
            gobject.IO_IN: u"IN",   # There is data to read.
1247
1287
            gobject.IO_OUT: u"OUT", # Data can be written (without
1259
1299
        logger.debug(u"Handling IPC: FD = %d, condition = %s", source,
1260
1300
                     conditions_string)
1261
1301
        
1262
 
        # Turn the pipe file descriptor into a Python file object
1263
 
        if source not in file_objects:
1264
 
            file_objects[source] = os.fdopen(source, u"r", 1)
1265
 
        
1266
1302
        # Read a line from the file object
1267
 
        cmdline = file_objects[source].readline()
 
1303
        cmdline = sender.readline()
1268
1304
        if not cmdline:             # Empty line means end of file
1269
 
            # close the IPC pipe
1270
 
            file_objects[source].close()
1271
 
            del file_objects[source]
 
1305
            # close the IPC pipes
 
1306
            sender.close()
 
1307
            reply.close()
1272
1308
            
1273
1309
            # Stop calling this function
1274
1310
            return False
1279
1315
        cmd, args = cmdline.rstrip(u"\r\n").split(None, 1)
1280
1316
        
1281
1317
        if cmd == u"NOTFOUND":
1282
 
            logger.warning(u"Client not found for fingerprint: %s",
1283
 
                           args)
 
1318
            fpr, address = args.split(None, 1)
 
1319
            logger.warning(u"Client not found for fingerprint: %s, ad"
 
1320
                           u"dress: %s", fpr, address)
1284
1321
            if self.use_dbus:
1285
1322
                # Emit D-Bus signal
1286
 
                mandos_dbus_service.ClientNotFound(args)
1287
 
        elif cmd == u"INVALID":
 
1323
                mandos_dbus_service.ClientNotFound(fpr, address)
 
1324
        elif cmd == u"DISABLED":
1288
1325
            for client in self.clients:
1289
1326
                if client.name == args:
1290
 
                    logger.warning(u"Client %s is invalid", args)
 
1327
                    logger.warning(u"Client %s is disabled", args)
1291
1328
                    if self.use_dbus:
1292
1329
                        # Emit D-Bus signal
1293
1330
                        client.Rejected()
1294
1331
                    break
1295
1332
            else:
1296
 
                logger.error(u"Unknown client %s is invalid", args)
 
1333
                logger.error(u"Unknown client %s is disabled", args)
1297
1334
        elif cmd == u"SENDING":
1298
1335
            for client in self.clients:
1299
1336
                if client.name == args:
1306
1343
            else:
1307
1344
                logger.error(u"Sending secret to unknown client %s",
1308
1345
                             args)
 
1346
        elif cmd == u"GETATTR":
 
1347
            attr_name, fpr = args.split(None, 1)
 
1348
            for client in self.clients:
 
1349
                if client.fingerprint == fpr:
 
1350
                    attr_value = getattr(client, attr_name, None)
 
1351
                    logger.debug("IPC reply: %r", attr_value)
 
1352
                    pickle.dump(attr_value, reply)
 
1353
                    break
 
1354
            else:
 
1355
                logger.error(u"Client %s on address %s requesting "
 
1356
                             u"attribute %s not found", fpr, address,
 
1357
                             attr_name)
 
1358
                pickle.dump(None, reply)
1309
1359
        else:
1310
1360
            logger.error(u"Unknown IPC command: %r", cmdline)
1311
1361
        
1345
1395
            elif suffix == u"w":
1346
1396
                delta = datetime.timedelta(0, 0, 0, 0, 0, 0, value)
1347
1397
            else:
1348
 
                raise ValueError
1349
 
        except (ValueError, IndexError):
1350
 
            raise ValueError
 
1398
                raise ValueError(u"Unknown suffix %r" % suffix)
 
1399
        except (ValueError, IndexError), e:
 
1400
            raise ValueError(e.message)
1351
1401
        timevalue += delta
1352
1402
    return timevalue
1353
1403
 
1366
1416
        def if_nametoindex(interface):
1367
1417
            "Get an interface index the hard way, i.e. using fcntl()"
1368
1418
            SIOCGIFINDEX = 0x8933  # From /usr/include/linux/sockios.h
1369
 
            with closing(socket.socket()) as s:
 
1419
            with contextlib.closing(socket.socket()) as s:
1370
1420
                ifreq = fcntl.ioctl(s, SIOCGIFINDEX,
1371
1421
                                    struct.pack(str(u"16s16x"),
1372
1422
                                                interface))
1566
1616
    bus = dbus.SystemBus()
1567
1617
    # End of Avahi example code
1568
1618
    if use_dbus:
1569
 
        bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos", bus)
 
1619
        try:
 
1620
            bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos",
 
1621
                                            bus, do_not_queue=True)
 
1622
        except dbus.exceptions.NameExistsException, e:
 
1623
            logger.error(unicode(e) + u", disabling D-Bus")
 
1624
            use_dbus = False
 
1625
            server_settings[u"use_dbus"] = False
 
1626
            tcp_server.use_dbus = False
1570
1627
    protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1571
1628
    service = AvahiService(name = server_settings[u"servicename"],
1572
1629
                           servicetype = u"_mandos._tcp",
1598
1655
        daemon()
1599
1656
    
1600
1657
    try:
1601
 
        with closing(pidfile):
 
1658
        with pidfile:
1602
1659
            pid = os.getpid()
1603
1660
            pidfile.write(str(pid) + "\n")
1604
1661
        del pidfile
1610
1667
        pass
1611
1668
    del pidfilename
1612
1669
    
1613
 
    def cleanup():
1614
 
        "Cleanup function; run on exit"
1615
 
        service.cleanup()
1616
 
        
1617
 
        while tcp_server.clients:
1618
 
            client = tcp_server.clients.pop()
1619
 
            client.disable_hook = None
1620
 
            client.disable()
1621
 
    
1622
 
    atexit.register(cleanup)
1623
 
    
1624
1670
    if not debug:
1625
1671
        signal.signal(signal.SIGINT, signal.SIG_IGN)
1626
1672
    signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
1633
1679
                dbus.service.Object.__init__(self, bus, u"/")
1634
1680
            _interface = u"se.bsnet.fukt.Mandos"
1635
1681
            
1636
 
            @dbus.service.signal(_interface, signature=u"oa{sv}")
1637
 
            def ClientAdded(self, objpath, properties):
 
1682
            @dbus.service.signal(_interface, signature=u"o")
 
1683
            def ClientAdded(self, objpath):
1638
1684
                "D-Bus signal"
1639
1685
                pass
1640
1686
            
1641
 
            @dbus.service.signal(_interface, signature=u"s")
1642
 
            def ClientNotFound(self, fingerprint):
 
1687
            @dbus.service.signal(_interface, signature=u"ss")
 
1688
            def ClientNotFound(self, fingerprint, address):
1643
1689
                "D-Bus signal"
1644
1690
                pass
1645
1691
            
1671
1717
                        tcp_server.clients.remove(c)
1672
1718
                        c.remove_from_connection()
1673
1719
                        # Don't signal anything except ClientRemoved
1674
 
                        c.disable(signal=False)
 
1720
                        c.disable(quiet=True)
1675
1721
                        # Emit D-Bus signal
1676
1722
                        self.ClientRemoved(object_path, c.name)
1677
1723
                        return
1678
 
                raise KeyError
 
1724
                raise KeyError(object_path)
1679
1725
            
1680
1726
            del _interface
1681
1727
        
1682
1728
        mandos_dbus_service = MandosDBusService()
1683
1729
    
 
1730
    def cleanup():
 
1731
        "Cleanup function; run on exit"
 
1732
        service.cleanup()
 
1733
        
 
1734
        while tcp_server.clients:
 
1735
            client = tcp_server.clients.pop()
 
1736
            if use_dbus:
 
1737
                client.remove_from_connection()
 
1738
            client.disable_hook = None
 
1739
            # Don't signal anything except ClientRemoved
 
1740
            client.disable(quiet=True)
 
1741
            if use_dbus:
 
1742
                # Emit D-Bus signal
 
1743
                mandos_dbus_service.ClientRemoved(client.dbus_object_path,
 
1744
                                                  client.name)
 
1745
    
 
1746
    atexit.register(cleanup)
 
1747
    
1684
1748
    for client in tcp_server.clients:
1685
1749
        if use_dbus:
1686
1750
            # Emit D-Bus signal
1687
 
            mandos_dbus_service.ClientAdded(client.dbus_object_path,
1688
 
                                            client.GetAll(u""))
 
1751
            mandos_dbus_service.ClientAdded(client.dbus_object_path)
1689
1752
        client.enable()
1690
1753
    
1691
1754
    tcp_server.enable()
1709
1772
            service.activate()
1710
1773
        except dbus.exceptions.DBusException, error:
1711
1774
            logger.critical(u"DBusException: %s", error)
 
1775
            cleanup()
1712
1776
            sys.exit(1)
1713
1777
        # End of Avahi example code
1714
1778
        
1721
1785
        main_loop.run()
1722
1786
    except AvahiError, error:
1723
1787
        logger.critical(u"AvahiError: %s", error)
 
1788
        cleanup()
1724
1789
        sys.exit(1)
1725
1790
    except KeyboardInterrupt:
1726
1791
        if debug:
1727
1792
            print >> sys.stderr
1728
1793
        logger.debug(u"Server received KeyboardInterrupt")
1729
1794
    logger.debug(u"Server exiting")
 
1795
    # Must run before the D-Bus bus name gets deregistered
 
1796
    cleanup()
1730
1797
 
1731
1798
if __name__ == '__main__':
1732
1799
    main()