/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: 2009-04-14 03:36:05 UTC
  • Revision ID: teddy@fukt.bsnet.se-20090414033605-ao45swlzyvmahc8y
Minor code cleanup, and a bug fix.

* mandos: Added blank second line in doc strings.
  (SO_BINDTODEVICE): New global constant.
  (TCP_handler): Renamed to "ClientHandler".  All users changed.
  (ClientHandler.handle): Get GnuTLS priority directly from
                          server.gnutls_priority instead of
                          server.settings["priority"].
  (IPv6_TCPServer): Do not use super() anywhere.
  (IPv6_TCPServer.__init__) Do not receive "settings" dict, get all
                            the relevant settings separately as
                            keyword arguments.  All callers changed.
  (IPv6_TCPServer.server_bind): Use global SO_BINDTODEVICE.  Bug fix:
                               add NUL character to interface name.
                               Use "self.interface" directly instead
                               of "self.settings['interface']".
  (IPv6_TCPServer.handle_ipc): Use "self.use_dbus" directly instead of
                               "self.settings['use_dbus']".

Show diffs side-by-side

added added

removed removed

Lines of Context:
66
66
import ctypes
67
67
import ctypes.util
68
68
 
 
69
try:
 
70
    SO_BINDTODEVICE = socket.SO_BINDTODEVICE
 
71
except AttributeError:
 
72
    try:
 
73
        from IN import SO_BINDTODEVICE
 
74
    except ImportError:
 
75
        # From /usr/include/asm/socket.h
 
76
        SO_BINDTODEVICE = 25
 
77
 
 
78
 
69
79
version = "1.0.8"
70
80
 
71
81
logger = logging.Logger('mandos')
98
108
 
99
109
class AvahiService(object):
100
110
    """An Avahi (Zeroconf) service.
 
111
    
101
112
    Attributes:
102
113
    interface: integer; avahi.IF_UNSPEC or an interface index.
103
114
               Used to optionally bind to the specified interface.
181
192
 
182
193
class Client(object):
183
194
    """A representation of a client host served by this server.
 
195
    
184
196
    Attributes:
185
197
    name:       string; from the config file, used in log messages and
186
198
                        D-Bus identifiers
317
329
    
318
330
    def checked_ok(self):
319
331
        """Bump up the timeout for this client.
 
332
        
320
333
        This should only be called when the client has been seen,
321
334
        alive and well.
322
335
        """
328
341
    
329
342
    def start_checker(self):
330
343
        """Start a new checker subprocess if one is not running.
 
344
        
331
345
        If a checker already exists, leave it running and do
332
346
        nothing."""
333
347
        # The reason for not killing a running checker is that if we
421
435
 
422
436
class ClientDBus(Client, dbus.service.Object):
423
437
    """A Client class using D-Bus
 
438
    
424
439
    Attributes:
425
440
    dbus_object_path: dbus.ObjectPath ; only set if self.use_dbus
426
441
    """
673
688
    del _interface
674
689
 
675
690
 
676
 
class TCP_handler(SocketServer.BaseRequestHandler, object):
677
 
    """A TCP request handler class.
678
 
    Instantiated by IPv6_TCPServer for each request to handle it.
 
691
class ClientHandler(SocketServer.BaseRequestHandler, object):
 
692
    """A class to handle client connections.
 
693
    
 
694
    Instantiated once for each connection to handle it.
679
695
    Note: This will run in its own forked process."""
680
696
    
681
697
    def handle(self):
708
724
            #                     "+COMP-NULL", "+CTYPE-OPENPGP",
709
725
            #                     "+DHE-DSS"))
710
726
            # Use a fallback default, since this MUST be set.
711
 
            priority = self.server.settings.get("priority", "NORMAL")
 
727
            priority = self.server.gnutls_priority
 
728
            if priority is None:
 
729
                priority = "NORMAL"
712
730
            (gnutls.library.functions
713
731
             .gnutls_priority_set_direct(session._c_object,
714
732
                                         priority, None))
820
838
 
821
839
class ForkingMixInWithPipe(SocketServer.ForkingMixIn, object):
822
840
    """Like SocketServer.ForkingMixIn, but also pass a pipe.
 
841
    
823
842
    Assumes a gobject.MainLoop event loop.
824
843
    """
825
844
    def process_request(self, request, client_address):
826
 
        """This overrides and wraps the original process_request().
 
845
        """Overrides and wraps the original process_request().
 
846
        
827
847
        This function creates a new pipe in self.pipe 
828
848
        """
829
849
        self.pipe = os.pipe()
843
863
class IPv6_TCPServer(ForkingMixInWithPipe,
844
864
                     SocketServer.TCPServer, object):
845
865
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
 
866
    
846
867
    Attributes:
847
 
        settings:       Server settings
 
868
        enabled:        Boolean; whether this server is activated yet
 
869
        interface:      None or a network interface name (string)
 
870
        use_ipv6:       Boolean; to use IPv6 or not
 
871
        ----
848
872
        clients:        Set() of Client objects
849
 
        enabled:        Boolean; whether this server is activated yet
 
873
        gnutls_priority GnuTLS priority string
 
874
        use_dbus:       Boolean; to emit D-Bus signals or not
850
875
    """
851
 
    address_family = socket.AF_INET6
852
 
    def __init__(self, *args, **kwargs):
853
 
        if "settings" in kwargs:
854
 
            self.settings = kwargs["settings"]
855
 
            del kwargs["settings"]
856
 
        if "clients" in kwargs:
857
 
            self.clients = kwargs["clients"]
858
 
            del kwargs["clients"]
859
 
        if "use_ipv6" in kwargs:
860
 
            if not kwargs["use_ipv6"]:
861
 
                self.address_family = socket.AF_INET
862
 
            del kwargs["use_ipv6"]
 
876
    def __init__(self, server_address, RequestHandlerClass,
 
877
                 interface=None, use_ipv6=True, clients=None,
 
878
                 gnutls_priority=None, use_dbus=True):
863
879
        self.enabled = False
864
 
        super(IPv6_TCPServer, self).__init__(*args, **kwargs)
 
880
        self.interface = interface
 
881
        if use_ipv6:
 
882
            self.address_family = socket.AF_INET6
 
883
        self.clients = clients
 
884
        self.use_dbus = use_dbus
 
885
        self.gnutls_priority = gnutls_priority
 
886
        SocketServer.TCPServer.__init__(self, server_address,
 
887
                                        RequestHandlerClass)
865
888
    def server_bind(self):
866
889
        """This overrides the normal server_bind() function
867
890
        to bind to an interface if one was specified, and also NOT to
868
891
        bind to an address or port if they were not specified."""
869
 
        if self.settings["interface"]:
870
 
            # 25 is from /usr/include/asm-i486/socket.h
871
 
            SO_BINDTODEVICE = getattr(socket, "SO_BINDTODEVICE", 25)
 
892
        if self.interface is not None:
872
893
            try:
873
894
                self.socket.setsockopt(socket.SOL_SOCKET,
874
895
                                       SO_BINDTODEVICE,
875
 
                                       self.settings["interface"])
 
896
                                       self.interface + '\0')
876
897
            except socket.error, error:
877
898
                if error[0] == errno.EPERM:
878
899
                    logger.error(u"No permission to"
879
900
                                 u" bind to interface %s",
880
 
                                 self.settings["interface"])
 
901
                                 self.interface)
881
902
                else:
882
903
                    raise
883
904
        # Only bind(2) the socket if we really need to.
892
913
            elif not self.server_address[1]:
893
914
                self.server_address = (self.server_address[0],
894
915
                                       0)
895
 
#                 if self.settings["interface"]:
 
916
#                 if self.interface:
896
917
#                     self.server_address = (self.server_address[0],
897
918
#                                            0, # port
898
919
#                                            0, # flowinfo
899
920
#                                            if_nametoindex
900
 
#                                            (self.settings
901
 
#                                             ["interface"]))
902
 
            return super(IPv6_TCPServer, self).server_bind()
 
921
#                                            (self.interface))
 
922
            return SocketServer.TCPServer.server_bind(self)
903
923
    def server_activate(self):
904
924
        if self.enabled:
905
 
            return super(IPv6_TCPServer, self).server_activate()
 
925
            return SocketServer.TCPServer.server_activate(self)
906
926
    def enable(self):
907
927
        self.enabled = True
908
928
    def handle_ipc(self, source, condition, file_objects={}):
945
965
        if cmd == "NOTFOUND":
946
966
            logger.warning(u"Client not found for fingerprint: %s",
947
967
                           args)
948
 
            if self.settings["use_dbus"]:
 
968
            if self.use_dbus:
949
969
                # Emit D-Bus signal
950
970
                mandos_dbus_service.ClientNotFound(args)
951
971
        elif cmd == "INVALID":
952
972
            for client in self.clients:
953
973
                if client.name == args:
954
974
                    logger.warning(u"Client %s is invalid", args)
955
 
                    if self.settings["use_dbus"]:
 
975
                    if self.use_dbus:
956
976
                        # Emit D-Bus signal
957
977
                        client.Rejected()
958
978
                    break
963
983
                if client.name == args:
964
984
                    logger.info(u"Sending secret to %s", client.name)
965
985
                    client.checked_ok()
966
 
                    if self.settings["use_dbus"]:
 
986
                    if self.use_dbus:
967
987
                        # Emit D-Bus signal
968
988
                        client.ReceivedSecret()
969
989
                    break
1064
1084
 
1065
1085
def daemon(nochdir = False, noclose = False):
1066
1086
    """See daemon(3).  Standard BSD Unix function.
 
1087
    
1067
1088
    This should really exist as os.daemon, but it doesn't (yet)."""
1068
1089
    if os.fork():
1069
1090
        sys.exit()
1197
1218
    clients = Set()
1198
1219
    tcp_server = IPv6_TCPServer((server_settings["address"],
1199
1220
                                 server_settings["port"]),
1200
 
                                TCP_handler,
1201
 
                                settings=server_settings,
1202
 
                                clients=clients, use_ipv6=use_ipv6)
 
1221
                                ClientHandler,
 
1222
                                interface=
 
1223
                                server_settings["interface"],
 
1224
                                use_ipv6=use_ipv6,
 
1225
                                clients=clients,
 
1226
                                gnutls_priority=
 
1227
                                server_settings["priority"],
 
1228
                                use_dbus=use_dbus)
1203
1229
    pidfilename = "/var/run/mandos.pid"
1204
1230
    try:
1205
1231
        pidfile = open(pidfilename, "w")