/mandos/release

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

« back to all changes in this revision

Viewing changes to mandos

Merge from pipe IPC branch.

* mandos (AvahiService.rename, main): Include PID in log messages when
                                      using a different service name.
  (Client.ReceivedSecret, Client.Rejected): New D-Bus signals.
  (TCP_handler.handle): Send IPC to parent process.
  (ForkingMixInWithPipe): New mixin class.
  (IPv6_TCPServer): Inherit from ForkingMixInWithPipe instead of
                    SocketServer.ForkingMixIn.
  (IPv6_TCPServer.handle_ipc): New method.
  (main/mandos_server): Renamed to "mandos_dbus_service" and made
                        global.
  (main/MandosServer): Renamed to "MandosDBusService".
  (main/MandosDBusService.ClientNotFound): New D-Bus signal.

Show diffs side-by-side

added added

removed removed

Lines of Context:
66
66
import ctypes
67
67
import ctypes.util
68
68
 
69
 
version = "1.0.5"
 
69
version = "1.0.8"
70
70
 
71
71
logger = logging.Logger('mandos')
72
72
syslogger = (logging.handlers.SysLogHandler
73
73
             (facility = logging.handlers.SysLogHandler.LOG_DAEMON,
74
74
              address = "/dev/log"))
75
75
syslogger.setFormatter(logging.Formatter
76
 
                       ('Mandos: %(levelname)s: %(message)s'))
 
76
                       ('Mandos [%(process)d]: %(levelname)s:'
 
77
                        ' %(message)s'))
77
78
logger.addHandler(syslogger)
78
79
 
79
80
console = logging.StreamHandler()
80
 
console.setFormatter(logging.Formatter('%(name)s: %(levelname)s:'
81
 
                                       ' %(message)s'))
 
81
console.setFormatter(logging.Formatter('%(name)s [%(process)d]:'
 
82
                                       ' %(levelname)s: %(message)s'))
82
83
logger.addHandler(console)
83
84
 
84
85
class AvahiError(Exception):
113
114
    """
114
115
    def __init__(self, interface = avahi.IF_UNSPEC, name = None,
115
116
                 servicetype = None, port = None, TXT = None,
116
 
                 domain = "", host = "", max_renames = 32768):
 
117
                 domain = "", host = "", max_renames = 32768,
 
118
                 protocol = avahi.PROTO_UNSPEC):
117
119
        self.interface = interface
118
120
        self.name = name
119
121
        self.type = servicetype
123
125
        self.host = host
124
126
        self.rename_count = 0
125
127
        self.max_renames = max_renames
 
128
        self.protocol = protocol
126
129
    def rename(self):
127
130
        """Derived from the Avahi example code"""
128
131
        if self.rename_count >= self.max_renames:
134
137
        logger.info(u"Changing Zeroconf service name to %r ...",
135
138
                    str(self.name))
136
139
        syslogger.setFormatter(logging.Formatter
137
 
                               ('Mandos (%s): %%(levelname)s:'
138
 
                                ' %%(message)s' % self.name))
 
140
                               ('Mandos (%s) [%%(process)d]:'
 
141
                                ' %%(levelname)s: %%(message)s'
 
142
                                % self.name))
139
143
        self.remove()
140
144
        self.add()
141
145
        self.rename_count += 1
157
161
                     service.name, service.type)
158
162
        group.AddService(
159
163
                self.interface,         # interface
160
 
                avahi.PROTO_INET6,      # protocol
 
164
                self.protocol,          # protocol
161
165
                dbus.UInt32(0),         # flags
162
166
                self.name, self.type,
163
167
                self.domain, self.host,
202
206
                     client lives.  %() expansions are done at
203
207
                     runtime with vars(self) as dict, so that for
204
208
                     instance %(name)s can be used in the command.
 
209
    current_checker_command: string; current running checker_command
205
210
    use_dbus: bool(); Whether to provide D-Bus interface and signals
206
211
    dbus_object_path: dbus.ObjectPath ; only set if self.use_dbus
207
212
    """
256
261
        self.disable_initiator_tag = None
257
262
        self.checker_callback_tag = None
258
263
        self.checker_command = config["checker"]
 
264
        self.current_checker_command = None
259
265
        self.last_connect = None
260
266
        # Only now, when this client is initialized, can it show up on
261
267
        # the D-Bus
376
382
        # checkers alone, the checker would have to take more time
377
383
        # than 'timeout' for the client to be declared invalid, which
378
384
        # is as it should be.
 
385
        
 
386
        # If a checker exists, make sure it is not a zombie
 
387
        if self.checker is not None:
 
388
            pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
 
389
            if pid:
 
390
                logger.warning("Checker was a zombie")
 
391
                gobject.source_remove(self.checker_callback_tag)
 
392
                self.checker_callback(pid, status,
 
393
                                      self.current_checker_command)
 
394
        # Start a new checker if needed
379
395
        if self.checker is None:
380
396
            try:
381
397
                # In case checker_command has exactly one % operator
391
407
                    logger.error(u'Could not format string "%s":'
392
408
                                 u' %s', self.checker_command, error)
393
409
                    return True # Try again later
 
410
                self.current_checker_command = command
394
411
            try:
395
412
                logger.info(u"Starting checker %r for %s",
396
413
                            command, self.name)
411
428
                                             (self.checker.pid,
412
429
                                              self.checker_callback,
413
430
                                              data=command))
 
431
                # The checker may have completed before the gobject
 
432
                # watch was added.  Check for this.
 
433
                pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
 
434
                if pid:
 
435
                    gobject.source_remove(self.checker_callback_tag)
 
436
                    self.checker_callback(pid, status, command)
414
437
            except OSError, error:
415
438
                logger.error(u"Failed to start subprocess: %s",
416
439
                             error)
520
543
        "D-Bus signal"
521
544
        pass
522
545
    
 
546
    # ReceivedSecret - signal
 
547
    @dbus.service.signal(_interface)
 
548
    def ReceivedSecret(self):
 
549
        "D-Bus signal"
 
550
        pass
 
551
    
 
552
    # Rejected - signal
 
553
    @dbus.service.signal(_interface)
 
554
    def Rejected(self):
 
555
        "D-Bus signal"
 
556
        pass
 
557
    
523
558
    # SetChecker - method
524
559
    @dbus.service.method(_interface, in_signature="s")
525
560
    def SetChecker(self, checker):
656
691
    def handle(self):
657
692
        logger.info(u"TCP connection from: %s",
658
693
                    unicode(self.client_address))
659
 
        session = (gnutls.connection
660
 
                   .ClientSession(self.request,
661
 
                                  gnutls.connection
662
 
                                  .X509Credentials()))
663
 
        
664
 
        line = self.request.makefile().readline()
665
 
        logger.debug(u"Protocol version: %r", line)
666
 
        try:
667
 
            if int(line.strip().split()[0]) > 1:
668
 
                raise RuntimeError
669
 
        except (ValueError, IndexError, RuntimeError), error:
670
 
            logger.error(u"Unknown protocol version: %s", error)
671
 
            return
672
 
        
673
 
        # Note: gnutls.connection.X509Credentials is really a generic
674
 
        # GnuTLS certificate credentials object so long as no X.509
675
 
        # keys are added to it.  Therefore, we can use it here despite
676
 
        # using OpenPGP certificates.
677
 
        
678
 
        #priority = ':'.join(("NONE", "+VERS-TLS1.1", "+AES-256-CBC",
679
 
        #                "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP",
680
 
        #                "+DHE-DSS"))
681
 
        # Use a fallback default, since this MUST be set.
682
 
        priority = self.server.settings.get("priority", "NORMAL")
683
 
        (gnutls.library.functions
684
 
         .gnutls_priority_set_direct(session._c_object,
685
 
                                     priority, None))
686
 
        
687
 
        try:
688
 
            session.handshake()
689
 
        except gnutls.errors.GNUTLSError, error:
690
 
            logger.warning(u"Handshake failed: %s", error)
691
 
            # Do not run session.bye() here: the session is not
692
 
            # established.  Just abandon the request.
693
 
            return
694
 
        logger.debug(u"Handshake succeeded")
695
 
        try:
696
 
            fpr = fingerprint(peer_certificate(session))
697
 
        except (TypeError, gnutls.errors.GNUTLSError), error:
698
 
            logger.warning(u"Bad certificate: %s", error)
699
 
            session.bye()
700
 
            return
701
 
        logger.debug(u"Fingerprint: %s", fpr)
702
 
        for c in self.server.clients:
703
 
            if c.fingerprint == fpr:
704
 
                client = c
705
 
                break
706
 
        else:
707
 
            logger.warning(u"Client not found for fingerprint: %s",
708
 
                           fpr)
709
 
            session.bye()
710
 
            return
711
 
        # Have to check if client.still_valid(), since it is possible
712
 
        # that the client timed out while establishing the GnuTLS
713
 
        # session.
714
 
        if not client.still_valid():
715
 
            logger.warning(u"Client %(name)s is invalid",
716
 
                           vars(client))
717
 
            session.bye()
718
 
            return
719
 
        ## This won't work here, since we're in a fork.
720
 
        # client.checked_ok()
721
 
        sent_size = 0
722
 
        while sent_size < len(client.secret):
723
 
            sent = session.send(client.secret[sent_size:])
724
 
            logger.debug(u"Sent: %d, remaining: %d",
725
 
                         sent, len(client.secret)
726
 
                         - (sent_size + sent))
727
 
            sent_size += sent
728
 
        session.bye()
729
 
 
730
 
 
731
 
class IPv6_TCPServer(SocketServer.ForkingMixIn,
 
694
        logger.debug(u"IPC Pipe FD: %d", self.server.pipe[1])
 
695
        # Open IPC pipe to parent process
 
696
        with closing(os.fdopen(self.server.pipe[1], "w", 1)) as ipc:
 
697
            session = (gnutls.connection
 
698
                       .ClientSession(self.request,
 
699
                                      gnutls.connection
 
700
                                      .X509Credentials()))
 
701
            
 
702
            line = self.request.makefile().readline()
 
703
            logger.debug(u"Protocol version: %r", line)
 
704
            try:
 
705
                if int(line.strip().split()[0]) > 1:
 
706
                    raise RuntimeError
 
707
            except (ValueError, IndexError, RuntimeError), error:
 
708
                logger.error(u"Unknown protocol version: %s", error)
 
709
                return
 
710
            
 
711
            # Note: gnutls.connection.X509Credentials is really a
 
712
            # generic GnuTLS certificate credentials object so long as
 
713
            # no X.509 keys are added to it.  Therefore, we can use it
 
714
            # here despite using OpenPGP certificates.
 
715
            
 
716
            #priority = ':'.join(("NONE", "+VERS-TLS1.1",
 
717
            #                     "+AES-256-CBC", "+SHA1",
 
718
            #                     "+COMP-NULL", "+CTYPE-OPENPGP",
 
719
            #                     "+DHE-DSS"))
 
720
            # Use a fallback default, since this MUST be set.
 
721
            priority = self.server.settings.get("priority", "NORMAL")
 
722
            (gnutls.library.functions
 
723
             .gnutls_priority_set_direct(session._c_object,
 
724
                                         priority, None))
 
725
            
 
726
            try:
 
727
                session.handshake()
 
728
            except gnutls.errors.GNUTLSError, error:
 
729
                logger.warning(u"Handshake failed: %s", error)
 
730
                # Do not run session.bye() here: the session is not
 
731
                # established.  Just abandon the request.
 
732
                return
 
733
            logger.debug(u"Handshake succeeded")
 
734
            try:
 
735
                fpr = fingerprint(peer_certificate(session))
 
736
            except (TypeError, gnutls.errors.GNUTLSError), error:
 
737
                logger.warning(u"Bad certificate: %s", error)
 
738
                session.bye()
 
739
                return
 
740
            logger.debug(u"Fingerprint: %s", fpr)
 
741
            
 
742
            for c in self.server.clients:
 
743
                if c.fingerprint == fpr:
 
744
                    client = c
 
745
                    break
 
746
            else:
 
747
                logger.warning(u"Client not found for fingerprint: %s",
 
748
                               fpr)
 
749
                ipc.write("NOTFOUND %s\n" % fpr)
 
750
                session.bye()
 
751
                return
 
752
            # Have to check if client.still_valid(), since it is
 
753
            # possible that the client timed out while establishing
 
754
            # the GnuTLS session.
 
755
            if not client.still_valid():
 
756
                logger.warning(u"Client %(name)s is invalid",
 
757
                               vars(client))
 
758
                ipc.write("INVALID %s\n" % client.name)
 
759
                session.bye()
 
760
                return
 
761
            ipc.write("SENDING %s\n" % client.name)
 
762
            sent_size = 0
 
763
            while sent_size < len(client.secret):
 
764
                sent = session.send(client.secret[sent_size:])
 
765
                logger.debug(u"Sent: %d, remaining: %d",
 
766
                             sent, len(client.secret)
 
767
                             - (sent_size + sent))
 
768
                sent_size += sent
 
769
            session.bye()
 
770
 
 
771
 
 
772
class ForkingMixInWithPipe(SocketServer.ForkingMixIn, object):
 
773
    """Like SocketServer.ForkingMixIn, but also pass a pipe.
 
774
    Assumes a gobject.MainLoop event loop.
 
775
    """
 
776
    def process_request(self, request, client_address):
 
777
        """This overrides and wraps the original process_request().
 
778
        This function creates a new pipe in self.pipe 
 
779
        """
 
780
        self.pipe = os.pipe()
 
781
        super(ForkingMixInWithPipe,
 
782
              self).process_request(request, client_address)
 
783
        os.close(self.pipe[1])  # close write end
 
784
        # Call "handle_ipc" for both data and EOF events
 
785
        gobject.io_add_watch(self.pipe[0],
 
786
                             gobject.IO_IN | gobject.IO_HUP,
 
787
                             self.handle_ipc)
 
788
    def handle_ipc(source, condition):
 
789
        """Dummy function; override as necessary"""
 
790
        os.close(source)
 
791
        return False
 
792
 
 
793
 
 
794
class IPv6_TCPServer(ForkingMixInWithPipe,
732
795
                     SocketServer.TCPServer, object):
733
 
    """IPv6 TCP server.  Accepts 'None' as address and/or port.
 
796
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
734
797
    Attributes:
735
798
        settings:       Server settings
736
799
        clients:        Set() of Client objects
744
807
        if "clients" in kwargs:
745
808
            self.clients = kwargs["clients"]
746
809
            del kwargs["clients"]
 
810
        if "use_ipv6" in kwargs:
 
811
            if not kwargs["use_ipv6"]:
 
812
                self.address_family = socket.AF_INET
 
813
            del kwargs["use_ipv6"]
747
814
        self.enabled = False
748
815
        super(IPv6_TCPServer, self).__init__(*args, **kwargs)
749
816
    def server_bind(self):
763
830
                                 u" bind to interface %s",
764
831
                                 self.settings["interface"])
765
832
                else:
766
 
                    raise error
 
833
                    raise
767
834
        # Only bind(2) the socket if we really need to.
768
835
        if self.server_address[0] or self.server_address[1]:
769
836
            if not self.server_address[0]:
770
 
                in6addr_any = "::"
771
 
                self.server_address = (in6addr_any,
 
837
                if self.address_family == socket.AF_INET6:
 
838
                    any_address = "::" # in6addr_any
 
839
                else:
 
840
                    any_address = socket.INADDR_ANY
 
841
                self.server_address = (any_address,
772
842
                                       self.server_address[1])
773
843
            elif not self.server_address[1]:
774
844
                self.server_address = (self.server_address[0],
786
856
            return super(IPv6_TCPServer, self).server_activate()
787
857
    def enable(self):
788
858
        self.enabled = True
 
859
    def handle_ipc(self, source, condition, file_objects={}):
 
860
        condition_names = {
 
861
            gobject.IO_IN: "IN", # There is data to read.
 
862
            gobject.IO_OUT: "OUT", # Data can be written (without
 
863
                                   # blocking).
 
864
            gobject.IO_PRI: "PRI", # There is urgent data to read.
 
865
            gobject.IO_ERR: "ERR", # Error condition.
 
866
            gobject.IO_HUP: "HUP"  # Hung up (the connection has been
 
867
                                   # broken, usually for pipes and
 
868
                                   # sockets).
 
869
            }
 
870
        conditions_string = ' | '.join(name
 
871
                                       for cond, name in
 
872
                                       condition_names.iteritems()
 
873
                                       if cond & condition)
 
874
        logger.debug("Handling IPC: FD = %d, condition = %s", source,
 
875
                     conditions_string)
 
876
        
 
877
        # Turn the pipe file descriptor into a Python file object
 
878
        if source not in file_objects:
 
879
            file_objects[source] = os.fdopen(source, "r", 1)
 
880
        
 
881
        # Read a line from the file object
 
882
        cmdline = file_objects[source].readline()
 
883
        if not cmdline:             # Empty line means end of file
 
884
            # close the IPC pipe
 
885
            file_objects[source].close()
 
886
            del file_objects[source]
 
887
            
 
888
            # Stop calling this function
 
889
            return False
 
890
        
 
891
        logger.debug("IPC command: %r\n" % cmdline)
 
892
        
 
893
        # Parse and act on command
 
894
        cmd, args = cmdline.split(None, 1)
 
895
        if cmd == "NOTFOUND":
 
896
            if self.settings["use_dbus"]:
 
897
                # Emit D-Bus signal
 
898
                mandos_dbus_service.ClientNotFound(args)
 
899
        elif cmd == "INVALID":
 
900
            if self.settings["use_dbus"]:
 
901
                for client in self.clients:
 
902
                    if client.name == args:
 
903
                        # Emit D-Bus signal
 
904
                        client.Rejected()
 
905
                        break
 
906
        elif cmd == "SENDING":
 
907
            for client in self.clients:
 
908
                if client.name == args:
 
909
                    client.checked_ok()
 
910
                    if self.settings["use_dbus"]:
 
911
                        # Emit D-Bus signal
 
912
                        client.ReceivedSecret()
 
913
                    break
 
914
        else:
 
915
            logger.error("Unknown IPC command: %r", cmdline)
 
916
        
 
917
        # Keep calling this function
 
918
        return True
789
919
 
790
920
 
791
921
def string_to_delta(interval):
792
922
    """Parse a string and return a datetime.timedelta
793
 
 
 
923
    
794
924
    >>> string_to_delta('7d')
795
925
    datetime.timedelta(7)
796
926
    >>> string_to_delta('60s')
897
1027
 
898
1028
 
899
1029
def main():
 
1030
    
 
1031
    ######################################################################
 
1032
    # Parsing of options, both command line and config file
 
1033
    
900
1034
    parser = optparse.OptionParser(version = "%%prog %s" % version)
901
1035
    parser.add_option("-i", "--interface", type="string",
902
1036
                      metavar="IF", help="Bind to interface IF")
921
1055
                      dest="use_dbus",
922
1056
                      help="Do not provide D-Bus system bus"
923
1057
                      " interface")
 
1058
    parser.add_option("--no-ipv6", action="store_false",
 
1059
                      dest="use_ipv6", help="Do not use IPv6")
924
1060
    options = parser.parse_args()[0]
925
1061
    
926
1062
    if options.check:
937
1073
                        "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
938
1074
                        "servicename": "Mandos",
939
1075
                        "use_dbus": "True",
 
1076
                        "use_ipv6": "True",
940
1077
                        }
941
1078
    
942
1079
    # Parse config file for server-global settings
950
1087
                                                        "debug")
951
1088
    server_settings["use_dbus"] = server_config.getboolean("DEFAULT",
952
1089
                                                           "use_dbus")
 
1090
    server_settings["use_ipv6"] = server_config.getboolean("DEFAULT",
 
1091
                                                           "use_ipv6")
953
1092
    if server_settings["port"]:
954
1093
        server_settings["port"] = server_config.getint("DEFAULT",
955
1094
                                                       "port")
959
1098
    # options, if set.
960
1099
    for option in ("interface", "address", "port", "debug",
961
1100
                   "priority", "servicename", "configdir",
962
 
                   "use_dbus"):
 
1101
                   "use_dbus", "use_ipv6"):
963
1102
        value = getattr(options, option)
964
1103
        if value is not None:
965
1104
            server_settings[option] = value
966
1105
    del options
967
1106
    # Now we have our good server settings in "server_settings"
968
1107
    
 
1108
    ##################################################################
 
1109
    
969
1110
    # For convenience
970
1111
    debug = server_settings["debug"]
971
1112
    use_dbus = server_settings["use_dbus"]
 
1113
    use_ipv6 = server_settings["use_ipv6"]
972
1114
    
973
1115
    if not debug:
974
1116
        syslogger.setLevel(logging.WARNING)
976
1118
    
977
1119
    if server_settings["servicename"] != "Mandos":
978
1120
        syslogger.setFormatter(logging.Formatter
979
 
                               ('Mandos (%s): %%(levelname)s:'
980
 
                                ' %%(message)s'
 
1121
                               ('Mandos (%s) [%%(process)d]:'
 
1122
                                ' %%(levelname)s: %%(message)s'
981
1123
                                % server_settings["servicename"]))
982
1124
    
983
1125
    # Parse config file with clients
989
1131
    client_config = ConfigParser.SafeConfigParser(client_defaults)
990
1132
    client_config.read(os.path.join(server_settings["configdir"],
991
1133
                                    "clients.conf"))
 
1134
 
 
1135
    global mandos_dbus_service
 
1136
    mandos_dbus_service = None
992
1137
    
993
1138
    clients = Set()
994
1139
    tcp_server = IPv6_TCPServer((server_settings["address"],
995
1140
                                 server_settings["port"]),
996
1141
                                TCP_handler,
997
1142
                                settings=server_settings,
998
 
                                clients=clients)
 
1143
                                clients=clients, use_ipv6=use_ipv6)
999
1144
    pidfilename = "/var/run/mandos.pid"
1000
1145
    try:
1001
1146
        pidfile = open(pidfilename, "w")
1002
 
    except IOError, error:
 
1147
    except IOError:
1003
1148
        logger.error("Could not open file %r", pidfilename)
1004
1149
    
1005
1150
    try:
1017
1162
                uid = 65534
1018
1163
                gid = 65534
1019
1164
    try:
 
1165
        os.setgid(gid)
1020
1166
        os.setuid(uid)
1021
 
        os.setgid(gid)
1022
1167
    except OSError, error:
1023
1168
        if error[0] != errno.EPERM:
1024
1169
            raise error
1025
1170
    
 
1171
    # Enable all possible GnuTLS debugging
 
1172
    if debug:
 
1173
        # "Use a log level over 10 to enable all debugging options."
 
1174
        # - GnuTLS manual
 
1175
        gnutls.library.functions.gnutls_global_set_log_level(11)
 
1176
        
 
1177
        @gnutls.library.types.gnutls_log_func
 
1178
        def debug_gnutls(level, string):
 
1179
            logger.debug("GnuTLS: %s", string[:-1])
 
1180
        
 
1181
        (gnutls.library.functions
 
1182
         .gnutls_global_set_log_function(debug_gnutls))
 
1183
    
1026
1184
    global service
 
1185
    protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1027
1186
    service = AvahiService(name = server_settings["servicename"],
1028
 
                           servicetype = "_mandos._tcp", )
 
1187
                           servicetype = "_mandos._tcp",
 
1188
                           protocol = protocol)
1029
1189
    if server_settings["interface"]:
1030
1190
        service.interface = (if_nametoindex
1031
1191
                             (server_settings["interface"]))
1065
1225
        daemon()
1066
1226
    
1067
1227
    try:
1068
 
        pid = os.getpid()
1069
 
        pidfile.write(str(pid) + "\n")
1070
 
        pidfile.close()
 
1228
        with closing(pidfile):
 
1229
            pid = os.getpid()
 
1230
            pidfile.write(str(pid) + "\n")
1071
1231
        del pidfile
1072
1232
    except IOError:
1073
1233
        logger.error(u"Could not write to file %r with PID %d",
1099
1259
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
1100
1260
    
1101
1261
    if use_dbus:
1102
 
        class MandosServer(dbus.service.Object):
 
1262
        class MandosDBusService(dbus.service.Object):
1103
1263
            """A D-Bus proxy object"""
1104
1264
            def __init__(self):
1105
1265
                dbus.service.Object.__init__(self, bus, "/")
1110
1270
                "D-Bus signal"
1111
1271
                pass
1112
1272
            
 
1273
            @dbus.service.signal(_interface, signature="s")
 
1274
            def ClientNotFound(self, fingerprint):
 
1275
                "D-Bus signal"
 
1276
                pass
 
1277
            
1113
1278
            @dbus.service.signal(_interface, signature="os")
1114
1279
            def ClientRemoved(self, objpath, name):
1115
1280
                "D-Bus signal"
1144
1309
            
1145
1310
            del _interface
1146
1311
        
1147
 
        mandos_server = MandosServer()
 
1312
        mandos_dbus_service = MandosDBusService()
1148
1313
    
1149
1314
    for client in clients:
1150
1315
        if use_dbus:
1151
1316
            # Emit D-Bus signal
1152
 
            mandos_server.ClientAdded(client.dbus_object_path,
1153
 
                                      client.GetAllProperties())
 
1317
            mandos_dbus_service.ClientAdded(client.dbus_object_path,
 
1318
                                            client.GetAllProperties())
1154
1319
        client.enable()
1155
1320
    
1156
1321
    tcp_server.enable()
1158
1323
    
1159
1324
    # Find out what port we got
1160
1325
    service.port = tcp_server.socket.getsockname()[1]
1161
 
    logger.info(u"Now listening on address %r, port %d, flowinfo %d,"
1162
 
                u" scope_id %d" % tcp_server.socket.getsockname())
 
1326
    if use_ipv6:
 
1327
        logger.info(u"Now listening on address %r, port %d,"
 
1328
                    " flowinfo %d, scope_id %d"
 
1329
                    % tcp_server.socket.getsockname())
 
1330
    else:                       # IPv4
 
1331
        logger.info(u"Now listening on address %r, port %d"
 
1332
                    % tcp_server.socket.getsockname())
1163
1333
    
1164
1334
    #service.interface = tcp_server.socket.getsockname()[3]
1165
1335
    
1185
1355
        sys.exit(1)
1186
1356
    except KeyboardInterrupt:
1187
1357
        if debug:
1188
 
            print
 
1358
            print >> sys.stderr
 
1359
        logger.debug("Server received KeyboardInterrupt")
 
1360
    logger.debug("Server exiting")
1189
1361
 
1190
1362
if __name__ == '__main__':
1191
1363
    main()