/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

* plugins.d/mandos-client.c: Merge unified printing system.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
# along with this program.  If not, see
29
29
# <http://www.gnu.org/licenses/>.
30
30
31
 
# Contact the authors at <mandos@fukt.bsnet.se>.
 
31
# Contact the authors at <mandos@recompile.se>.
32
32
33
33
 
34
34
from __future__ import (division, absolute_import, print_function,
62
62
import functools
63
63
import cPickle as pickle
64
64
import multiprocessing
 
65
import types
65
66
 
66
67
import dbus
67
68
import dbus.service
82
83
        SO_BINDTODEVICE = None
83
84
 
84
85
 
85
 
version = "1.3.1"
 
86
version = "1.4.1"
86
87
 
87
88
#logger = logging.getLogger('mandos')
88
89
logger = logging.Logger('mandos')
159
160
                            " after %i retries, exiting.",
160
161
                            self.rename_count)
161
162
            raise AvahiServiceError("Too many renames")
162
 
        self.name = unicode(self.server.GetAlternativeServiceName(self.name))
 
163
        self.name = unicode(self.server
 
164
                            .GetAlternativeServiceName(self.name))
163
165
        logger.info("Changing Zeroconf service name to %r ...",
164
166
                    self.name)
165
167
        syslogger.setFormatter(logging.Formatter
313
315
                          "created", "enabled", "fingerprint",
314
316
                          "host", "interval", "last_checked_ok",
315
317
                          "last_enabled", "name", "timeout")
316
 
        
 
318
    
317
319
    def timeout_milliseconds(self):
318
320
        "Return the 'timeout' attribute in milliseconds"
319
321
        return _timedelta_to_milliseconds(self.timeout)
320
 
 
 
322
    
321
323
    def extended_timeout_milliseconds(self):
322
324
        "Return the 'extended_timeout' attribute in milliseconds"
323
 
        return _timedelta_to_milliseconds(self.extended_timeout)    
 
325
        return _timedelta_to_milliseconds(self.extended_timeout)
324
326
    
325
327
    def interval_milliseconds(self):
326
328
        "Return the 'interval' attribute in milliseconds"
327
329
        return _timedelta_to_milliseconds(self.interval)
328
 
 
 
330
    
329
331
    def approval_delay_milliseconds(self):
330
332
        return _timedelta_to_milliseconds(self.approval_delay)
331
333
    
360
362
        self.last_enabled = None
361
363
        self.last_checked_ok = None
362
364
        self.timeout = string_to_delta(config["timeout"])
363
 
        self.extended_timeout = string_to_delta(config["extended_timeout"])
 
365
        self.extended_timeout = string_to_delta(config
 
366
                                                ["extended_timeout"])
364
367
        self.interval = string_to_delta(config["interval"])
365
368
        self.disable_hook = disable_hook
366
369
        self.checker = None
379
382
            config["approval_delay"])
380
383
        self.approval_duration = string_to_delta(
381
384
            config["approval_duration"])
382
 
        self.changedstate = multiprocessing_manager.Condition(multiprocessing_manager.Lock())
 
385
        self.changedstate = (multiprocessing_manager
 
386
                             .Condition(multiprocessing_manager
 
387
                                        .Lock()))
383
388
    
384
389
    def send_changedstate(self):
385
390
        self.changedstate.acquire()
386
391
        self.changedstate.notify_all()
387
392
        self.changedstate.release()
388
 
        
 
393
    
389
394
    def enable(self):
390
395
        """Start this client's checker and timeout hooks"""
391
396
        if getattr(self, "enabled", False):
459
464
        if timeout is None:
460
465
            timeout = self.timeout
461
466
        self.last_checked_ok = datetime.datetime.utcnow()
462
 
        gobject.source_remove(self.disable_initiator_tag)
463
 
        self.expires = datetime.datetime.utcnow() + timeout
464
 
        self.disable_initiator_tag = (gobject.timeout_add
465
 
                                      (_timedelta_to_milliseconds(timeout),
466
 
                                       self.disable))
 
467
        if self.disable_initiator_tag is not None:
 
468
            gobject.source_remove(self.disable_initiator_tag)
 
469
        if getattr(self, "enabled", False):
 
470
            self.disable_initiator_tag = (gobject.timeout_add
 
471
                                          (_timedelta_to_milliseconds
 
472
                                           (timeout), self.disable))
 
473
            self.expires = datetime.datetime.utcnow() + timeout
467
474
    
468
475
    def need_approval(self):
469
476
        self.last_approval_request = datetime.datetime.utcnow()
509
516
                                       'replace')))
510
517
                    for attr in
511
518
                    self.runtime_expansions)
512
 
 
 
519
                
513
520
                try:
514
521
                    command = self.checker_command % escaped_attrs
515
522
                except TypeError as error:
561
568
                raise
562
569
        self.checker = None
563
570
 
 
571
 
564
572
def dbus_service_property(dbus_interface, signature="v",
565
573
                          access="readwrite", byte_arrays=False):
566
574
    """Decorators for marking methods of a DBusObjectWithProperties to
612
620
 
613
621
class DBusObjectWithProperties(dbus.service.Object):
614
622
    """A D-Bus object with properties.
615
 
 
 
623
    
616
624
    Classes inheriting from this can use the dbus_service_property
617
625
    decorator to expose methods as D-Bus properties.  It exposes the
618
626
    standard Get(), Set(), and GetAll() methods on the D-Bus.
625
633
    def _get_all_dbus_properties(self):
626
634
        """Returns a generator of (name, attribute) pairs
627
635
        """
628
 
        return ((prop._dbus_name, prop)
 
636
        return ((prop.__get__(self)._dbus_name, prop.__get__(self))
 
637
                for cls in self.__class__.__mro__
629
638
                for name, prop in
630
 
                inspect.getmembers(self, self._is_dbus_property))
 
639
                inspect.getmembers(cls, self._is_dbus_property))
631
640
    
632
641
    def _get_dbus_property(self, interface_name, property_name):
633
642
        """Returns a bound method if one exists which is a D-Bus
634
643
        property with the specified name and interface.
635
644
        """
636
 
        for name in (property_name,
637
 
                     property_name + "_dbus_property"):
638
 
            prop = getattr(self, name, None)
639
 
            if (prop is None
640
 
                or not self._is_dbus_property(prop)
641
 
                or prop._dbus_name != property_name
642
 
                or (interface_name and prop._dbus_interface
643
 
                    and interface_name != prop._dbus_interface)):
644
 
                continue
645
 
            return prop
 
645
        for cls in  self.__class__.__mro__:
 
646
            for name, value in (inspect.getmembers
 
647
                                (cls, self._is_dbus_property)):
 
648
                if (value._dbus_name == property_name
 
649
                    and value._dbus_interface == interface_name):
 
650
                    return value.__get__(self)
 
651
        
646
652
        # No such property
647
653
        raise DBusPropertyNotFound(self.dbus_object_path + ":"
648
654
                                   + interface_name + "."
682
688
    def GetAll(self, interface_name):
683
689
        """Standard D-Bus property GetAll() method, see D-Bus
684
690
        standard.
685
 
 
 
691
        
686
692
        Note: Will not include properties with access="write".
687
693
        """
688
694
        all = {}
757
763
    return dbus.String(dt.isoformat(),
758
764
                       variant_level=variant_level)
759
765
 
 
766
class AlternateDBusNamesMetaclass(DBusObjectWithProperties
 
767
                                  .__metaclass__):
 
768
    """Applied to an empty subclass of a D-Bus object, this metaclass
 
769
    will add additional D-Bus attributes matching a certain pattern.
 
770
    """
 
771
    def __new__(mcs, name, bases, attr):
 
772
        # Go through all the base classes which could have D-Bus
 
773
        # methods, signals, or properties in them
 
774
        for base in (b for b in bases
 
775
                     if issubclass(b, dbus.service.Object)):
 
776
            # Go though all attributes of the base class
 
777
            for attrname, attribute in inspect.getmembers(base):
 
778
                # Ignore non-D-Bus attributes, and D-Bus attributes
 
779
                # with the wrong interface name
 
780
                if (not hasattr(attribute, "_dbus_interface")
 
781
                    or not attribute._dbus_interface
 
782
                    .startswith("se.recompile.Mandos")):
 
783
                    continue
 
784
                # Create an alternate D-Bus interface name based on
 
785
                # the current name
 
786
                alt_interface = (attribute._dbus_interface
 
787
                                 .replace("se.recompile.Mandos",
 
788
                                          "se.bsnet.fukt.Mandos"))
 
789
                # Is this a D-Bus signal?
 
790
                if getattr(attribute, "_dbus_is_signal", False):
 
791
                    # Extract the original non-method function by
 
792
                    # black magic
 
793
                    nonmethod_func = (dict(
 
794
                            zip(attribute.func_code.co_freevars,
 
795
                                attribute.__closure__))["func"]
 
796
                                      .cell_contents)
 
797
                    # Create a new, but exactly alike, function
 
798
                    # object, and decorate it to be a new D-Bus signal
 
799
                    # with the alternate D-Bus interface name
 
800
                    new_function = (dbus.service.signal
 
801
                                    (alt_interface,
 
802
                                     attribute._dbus_signature)
 
803
                                    (types.FunctionType(
 
804
                                nonmethod_func.func_code,
 
805
                                nonmethod_func.func_globals,
 
806
                                nonmethod_func.func_name,
 
807
                                nonmethod_func.func_defaults,
 
808
                                nonmethod_func.func_closure)))
 
809
                    # Define a creator of a function to call both the
 
810
                    # old and new functions, so both the old and new
 
811
                    # signals gets sent when the function is called
 
812
                    def fixscope(func1, func2):
 
813
                        """This function is a scope container to pass
 
814
                        func1 and func2 to the "call_both" function
 
815
                        outside of its arguments"""
 
816
                        def call_both(*args, **kwargs):
 
817
                            """This function will emit two D-Bus
 
818
                            signals by calling func1 and func2"""
 
819
                            func1(*args, **kwargs)
 
820
                            func2(*args, **kwargs)
 
821
                        return call_both
 
822
                    # Create the "call_both" function and add it to
 
823
                    # the class
 
824
                    attr[attrname] = fixscope(attribute,
 
825
                                              new_function)
 
826
                # Is this a D-Bus method?
 
827
                elif getattr(attribute, "_dbus_is_method", False):
 
828
                    # Create a new, but exactly alike, function
 
829
                    # object.  Decorate it to be a new D-Bus method
 
830
                    # with the alternate D-Bus interface name.  Add it
 
831
                    # to the class.
 
832
                    attr[attrname] = (dbus.service.method
 
833
                                      (alt_interface,
 
834
                                       attribute._dbus_in_signature,
 
835
                                       attribute._dbus_out_signature)
 
836
                                      (types.FunctionType
 
837
                                       (attribute.func_code,
 
838
                                        attribute.func_globals,
 
839
                                        attribute.func_name,
 
840
                                        attribute.func_defaults,
 
841
                                        attribute.func_closure)))
 
842
                # Is this a D-Bus property?
 
843
                elif getattr(attribute, "_dbus_is_property", False):
 
844
                    # Create a new, but exactly alike, function
 
845
                    # object, and decorate it to be a new D-Bus
 
846
                    # property with the alternate D-Bus interface
 
847
                    # name.  Add it to the class.
 
848
                    attr[attrname] = (dbus_service_property
 
849
                                      (alt_interface,
 
850
                                       attribute._dbus_signature,
 
851
                                       attribute._dbus_access,
 
852
                                       attribute
 
853
                                       ._dbus_get_args_options
 
854
                                       ["byte_arrays"])
 
855
                                      (types.FunctionType
 
856
                                       (attribute.func_code,
 
857
                                        attribute.func_globals,
 
858
                                        attribute.func_name,
 
859
                                        attribute.func_defaults,
 
860
                                        attribute.func_closure)))
 
861
        return type.__new__(mcs, name, bases, attr)
 
862
 
760
863
class ClientDBus(Client, DBusObjectWithProperties):
761
864
    """A Client class using D-Bus
762
865
    
787
890
    def notifychangeproperty(transform_func,
788
891
                             dbus_name, type_func=lambda x: x,
789
892
                             variant_level=1):
790
 
        """ Modify a variable so that its a property that announce its
791
 
        changes to DBus.
792
 
        transform_fun: Function that takes a value and transform it to
793
 
                       DBus type.
794
 
        dbus_name: DBus name of the variable
 
893
        """ Modify a variable so that it's a property which announces
 
894
        its changes to DBus.
 
895
 
 
896
        transform_fun: Function that takes a value and a variant_level
 
897
                       and transforms it to a D-Bus type.
 
898
        dbus_name: D-Bus name of the variable
795
899
        type_func: Function that transform the value before sending it
796
 
                   to DBus
797
 
        variant_level: DBus variant level. default: 1
 
900
                   to the D-Bus.  Default: no transform
 
901
        variant_level: D-Bus variant level.  Default: 1
798
902
        """
799
 
        real_value = [None,]
 
903
        attrname = "_{0}".format(dbus_name)
800
904
        def setter(self, value):
801
 
            old_value = real_value[0]
802
 
            real_value[0] = value
803
905
            if hasattr(self, "dbus_object_path"):
804
 
                if type_func(old_value) != type_func(real_value[0]):
805
 
                    dbus_value = transform_func(type_func(real_value[0]),
806
 
                                                variant_level)
 
906
                if (not hasattr(self, attrname) or
 
907
                    type_func(getattr(self, attrname, None))
 
908
                    != type_func(value)):
 
909
                    dbus_value = transform_func(type_func(value),
 
910
                                                variant_level
 
911
                                                =variant_level)
807
912
                    self.PropertyChanged(dbus.String(dbus_name),
808
913
                                         dbus_value)
809
 
 
810
 
        return property(lambda self: real_value[0], setter)
811
 
 
812
 
 
 
914
            setattr(self, attrname, value)
 
915
        
 
916
        return property(lambda self: getattr(self, attrname), setter)
 
917
    
 
918
    
813
919
    expires = notifychangeproperty(datetime_to_dbus, "Expires")
814
920
    approvals_pending = notifychangeproperty(dbus.Boolean,
815
921
                                             "ApprovalPending",
818
924
    last_enabled = notifychangeproperty(datetime_to_dbus,
819
925
                                        "LastEnabled")
820
926
    checker = notifychangeproperty(dbus.Boolean, "CheckerRunning",
821
 
                                   type_func = lambda checker: checker is not None)
 
927
                                   type_func = lambda checker:
 
928
                                       checker is not None)
822
929
    last_checked_ok = notifychangeproperty(datetime_to_dbus,
823
930
                                           "LastCheckedOK")
824
 
    last_approval_request = notifychangeproperty(datetime_to_dbus,
825
 
                                                 "LastApprovalRequest")
 
931
    last_approval_request = notifychangeproperty(
 
932
        datetime_to_dbus, "LastApprovalRequest")
826
933
    approved_by_default = notifychangeproperty(dbus.Boolean,
827
934
                                               "ApprovedByDefault")
828
 
    approval_delay = notifychangeproperty(dbus.UInt16, "ApprovalDelay",
829
 
                                          type_func = _timedelta_to_milliseconds)
830
 
    approval_duration = notifychangeproperty(dbus.UInt16, "ApprovalDuration",
831
 
                                             type_func = _timedelta_to_milliseconds)
 
935
    approval_delay = notifychangeproperty(dbus.UInt16,
 
936
                                          "ApprovalDelay",
 
937
                                          type_func =
 
938
                                          _timedelta_to_milliseconds)
 
939
    approval_duration = notifychangeproperty(
 
940
        dbus.UInt16, "ApprovalDuration",
 
941
        type_func = _timedelta_to_milliseconds)
832
942
    host = notifychangeproperty(dbus.String, "Host")
833
943
    timeout = notifychangeproperty(dbus.UInt16, "Timeout",
834
 
                                   type_func = _timedelta_to_milliseconds)
835
 
    extended_timeout = notifychangeproperty(dbus.UInt16, "ExtendedTimeout",
836
 
                                            type_func = _timedelta_to_milliseconds)
837
 
    interval = notifychangeproperty(dbus.UInt16, "Interval",
838
 
                                    type_func = _timedelta_to_milliseconds)
 
944
                                   type_func =
 
945
                                   _timedelta_to_milliseconds)
 
946
    extended_timeout = notifychangeproperty(
 
947
        dbus.UInt16, "ExtendedTimeout",
 
948
        type_func = _timedelta_to_milliseconds)
 
949
    interval = notifychangeproperty(dbus.UInt16,
 
950
                                    "Interval",
 
951
                                    type_func =
 
952
                                    _timedelta_to_milliseconds)
839
953
    checker_command = notifychangeproperty(dbus.String, "Checker")
840
954
    
841
955
    del notifychangeproperty
867
981
        
868
982
        return Client.checker_callback(self, pid, condition, command,
869
983
                                       *args, **kwargs)
870
 
 
 
984
    
871
985
    def start_checker(self, *args, **kwargs):
872
986
        old_checker = self.checker
873
987
        if self.checker is not None:
895
1009
    
896
1010
    
897
1011
    ## D-Bus methods, signals & properties
898
 
    _interface = "se.bsnet.fukt.Mandos.Client"
 
1012
    _interface = "se.recompile.Mandos.Client"
899
1013
    
900
1014
    ## Signals
901
1015
    
1076
1190
        gobject.source_remove(self.disable_initiator_tag)
1077
1191
        self.disable_initiator_tag = None
1078
1192
        self.expires = None
1079
 
        time_to_die = (self.
1080
 
                       _timedelta_to_milliseconds((self
1081
 
                                                   .last_checked_ok
1082
 
                                                   + self.timeout)
1083
 
                                                  - datetime.datetime
1084
 
                                                  .utcnow()))
 
1193
        time_to_die = _timedelta_to_milliseconds((self
 
1194
                                                  .last_checked_ok
 
1195
                                                  + self.timeout)
 
1196
                                                 - datetime.datetime
 
1197
                                                 .utcnow())
1085
1198
        if time_to_die <= 0:
1086
1199
            # The timeout has passed
1087
1200
            self.disable()
1088
1201
        else:
1089
1202
            self.expires = (datetime.datetime.utcnow()
1090
 
                            + datetime.timedelta(milliseconds = time_to_die))
 
1203
                            + datetime.timedelta(milliseconds =
 
1204
                                                 time_to_die))
1091
1205
            self.disable_initiator_tag = (gobject.timeout_add
1092
1206
                                          (time_to_die, self.disable))
1093
 
 
 
1207
    
1094
1208
    # ExtendedTimeout - property
1095
1209
    @dbus_service_property(_interface, signature="t",
1096
1210
                           access="readwrite")
1098
1212
        if value is None:       # get
1099
1213
            return dbus.UInt64(self.extended_timeout_milliseconds())
1100
1214
        self.extended_timeout = datetime.timedelta(0, 0, 0, value)
1101
 
 
 
1215
    
1102
1216
    # Interval - property
1103
1217
    @dbus_service_property(_interface, signature="t",
1104
1218
                           access="readwrite")
1113
1227
        self.checker_initiator_tag = (gobject.timeout_add
1114
1228
                                      (value, self.start_checker))
1115
1229
        self.start_checker()    # Start one now, too
1116
 
 
 
1230
    
1117
1231
    # Checker - property
1118
1232
    @dbus_service_property(_interface, signature="s",
1119
1233
                           access="readwrite")
1153
1267
        self._pipe.send(('init', fpr, address))
1154
1268
        if not self._pipe.recv():
1155
1269
            raise KeyError()
1156
 
 
 
1270
    
1157
1271
    def __getattribute__(self, name):
1158
1272
        if(name == '_pipe'):
1159
1273
            return super(ProxyClient, self).__getattribute__(name)
1166
1280
                self._pipe.send(('funcall', name, args, kwargs))
1167
1281
                return self._pipe.recv()[1]
1168
1282
            return func
1169
 
 
 
1283
    
1170
1284
    def __setattr__(self, name, value):
1171
1285
        if(name == '_pipe'):
1172
1286
            return super(ProxyClient, self).__setattr__(name, value)
1173
1287
        self._pipe.send(('setattr', name, value))
1174
1288
 
 
1289
class ClientDBusTransitional(ClientDBus):
 
1290
    __metaclass__ = AlternateDBusNamesMetaclass
1175
1291
 
1176
1292
class ClientHandler(socketserver.BaseRequestHandler, object):
1177
1293
    """A class to handle client connections.
1185
1301
                        unicode(self.client_address))
1186
1302
            logger.debug("Pipe FD: %d",
1187
1303
                         self.server.child_pipe.fileno())
1188
 
 
 
1304
            
1189
1305
            session = (gnutls.connection
1190
1306
                       .ClientSession(self.request,
1191
1307
                                      gnutls.connection
1192
1308
                                      .X509Credentials()))
1193
 
 
 
1309
            
1194
1310
            # Note: gnutls.connection.X509Credentials is really a
1195
1311
            # generic GnuTLS certificate credentials object so long as
1196
1312
            # no X.509 keys are added to it.  Therefore, we can use it
1197
1313
            # here despite using OpenPGP certificates.
1198
 
 
 
1314
            
1199
1315
            #priority = ':'.join(("NONE", "+VERS-TLS1.1",
1200
1316
            #                      "+AES-256-CBC", "+SHA1",
1201
1317
            #                      "+COMP-NULL", "+CTYPE-OPENPGP",
1207
1323
            (gnutls.library.functions
1208
1324
             .gnutls_priority_set_direct(session._c_object,
1209
1325
                                         priority, None))
1210
 
 
 
1326
            
1211
1327
            # Start communication using the Mandos protocol
1212
1328
            # Get protocol number
1213
1329
            line = self.request.makefile().readline()
1218
1334
            except (ValueError, IndexError, RuntimeError) as error:
1219
1335
                logger.error("Unknown protocol version: %s", error)
1220
1336
                return
1221
 
 
 
1337
            
1222
1338
            # Start GnuTLS connection
1223
1339
            try:
1224
1340
                session.handshake()
1228
1344
                # established.  Just abandon the request.
1229
1345
                return
1230
1346
            logger.debug("Handshake succeeded")
1231
 
 
 
1347
            
1232
1348
            approval_required = False
1233
1349
            try:
1234
1350
                try:
1239
1355
                    logger.warning("Bad certificate: %s", error)
1240
1356
                    return
1241
1357
                logger.debug("Fingerprint: %s", fpr)
1242
 
 
 
1358
                
1243
1359
                try:
1244
1360
                    client = ProxyClient(child_pipe, fpr,
1245
1361
                                         self.client_address)
1257
1373
                                       client.name)
1258
1374
                        if self.server.use_dbus:
1259
1375
                            # Emit D-Bus signal
1260
 
                            client.Rejected("Disabled")                    
 
1376
                            client.Rejected("Disabled")
1261
1377
                        return
1262
1378
                    
1263
1379
                    if client._approved or not client.approval_delay:
1280
1396
                        return
1281
1397
                    
1282
1398
                    #wait until timeout or approved
1283
 
                    #x = float(client._timedelta_to_milliseconds(delay))
1284
1399
                    time = datetime.datetime.now()
1285
1400
                    client.changedstate.acquire()
1286
 
                    client.changedstate.wait(float(client._timedelta_to_milliseconds(delay) / 1000))
 
1401
                    (client.changedstate.wait
 
1402
                     (float(client._timedelta_to_milliseconds(delay)
 
1403
                            / 1000)))
1287
1404
                    client.changedstate.release()
1288
1405
                    time2 = datetime.datetime.now()
1289
1406
                    if (time2 - time) >= delay:
1311
1428
                                 sent, len(client.secret)
1312
1429
                                 - (sent_size + sent))
1313
1430
                    sent_size += sent
1314
 
 
 
1431
                
1315
1432
                logger.info("Sending secret to %s", client.name)
1316
 
                # bump the timeout as if seen
 
1433
                # bump the timeout using extended_timeout
1317
1434
                client.checked_ok(client.extended_timeout)
1318
1435
                if self.server.use_dbus:
1319
1436
                    # Emit D-Bus signal
1399
1516
        except:
1400
1517
            self.handle_error(request, address)
1401
1518
        self.close_request(request)
1402
 
            
 
1519
    
1403
1520
    def process_request(self, request, address):
1404
1521
        """Start a new process to process the request."""
1405
 
        multiprocessing.Process(target = self.sub_process_main,
1406
 
                                args = (request, address)).start()
 
1522
        proc = multiprocessing.Process(target = self.sub_process_main,
 
1523
                                       args = (request,
 
1524
                                               address))
 
1525
        proc.start()
 
1526
        return proc
 
1527
 
1407
1528
 
1408
1529
class MultiprocessingMixInWithPipe(MultiprocessingMixIn, object):
1409
1530
    """ adds a pipe to the MixIn """
1413
1534
        This function creates a new pipe in self.pipe
1414
1535
        """
1415
1536
        parent_pipe, self.child_pipe = multiprocessing.Pipe()
1416
 
 
1417
 
        super(MultiprocessingMixInWithPipe,
1418
 
              self).process_request(request, client_address)
 
1537
        
 
1538
        proc = MultiprocessingMixIn.process_request(self, request,
 
1539
                                                    client_address)
1419
1540
        self.child_pipe.close()
1420
 
        self.add_pipe(parent_pipe)
1421
 
 
1422
 
    def add_pipe(self, parent_pipe):
 
1541
        self.add_pipe(parent_pipe, proc)
 
1542
    
 
1543
    def add_pipe(self, parent_pipe, proc):
1423
1544
        """Dummy function; override as necessary"""
1424
1545
        raise NotImplementedError
1425
1546
 
 
1547
 
1426
1548
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
1427
1549
                     socketserver.TCPServer, object):
1428
1550
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
1512
1634
    def server_activate(self):
1513
1635
        if self.enabled:
1514
1636
            return socketserver.TCPServer.server_activate(self)
 
1637
    
1515
1638
    def enable(self):
1516
1639
        self.enabled = True
1517
 
    def add_pipe(self, parent_pipe):
 
1640
    
 
1641
    def add_pipe(self, parent_pipe, proc):
1518
1642
        # Call "handle_ipc" for both data and EOF events
1519
1643
        gobject.io_add_watch(parent_pipe.fileno(),
1520
1644
                             gobject.IO_IN | gobject.IO_HUP,
1521
1645
                             functools.partial(self.handle_ipc,
1522
 
                                               parent_pipe = parent_pipe))
1523
 
        
 
1646
                                               parent_pipe =
 
1647
                                               parent_pipe,
 
1648
                                               proc = proc))
 
1649
    
1524
1650
    def handle_ipc(self, source, condition, parent_pipe=None,
1525
 
                   client_object=None):
 
1651
                   proc = None, client_object=None):
1526
1652
        condition_names = {
1527
1653
            gobject.IO_IN: "IN",   # There is data to read.
1528
1654
            gobject.IO_OUT: "OUT", # Data can be written (without
1537
1663
                                       for cond, name in
1538
1664
                                       condition_names.iteritems()
1539
1665
                                       if cond & condition)
1540
 
        # error or the other end of multiprocessing.Pipe has closed
 
1666
        # error, or the other end of multiprocessing.Pipe has closed
1541
1667
        if condition & (gobject.IO_ERR | condition & gobject.IO_HUP):
 
1668
            # Wait for other process to exit
 
1669
            proc.join()
1542
1670
            return False
1543
1671
        
1544
1672
        # Read a request from the child
1558
1686
                            "dress: %s", fpr, address)
1559
1687
                if self.use_dbus:
1560
1688
                    # Emit D-Bus signal
1561
 
                    mandos_dbus_service.ClientNotFound(fpr, address[0])
 
1689
                    mandos_dbus_service.ClientNotFound(fpr,
 
1690
                                                       address[0])
1562
1691
                parent_pipe.send(False)
1563
1692
                return False
1564
1693
            
1565
1694
            gobject.io_add_watch(parent_pipe.fileno(),
1566
1695
                                 gobject.IO_IN | gobject.IO_HUP,
1567
1696
                                 functools.partial(self.handle_ipc,
1568
 
                                                   parent_pipe = parent_pipe,
1569
 
                                                   client_object = client))
 
1697
                                                   parent_pipe =
 
1698
                                                   parent_pipe,
 
1699
                                                   proc = proc,
 
1700
                                                   client_object =
 
1701
                                                   client))
1570
1702
            parent_pipe.send(True)
1571
 
            # remove the old hook in favor of the new above hook on same fileno
 
1703
            # remove the old hook in favor of the new above hook on
 
1704
            # same fileno
1572
1705
            return False
1573
1706
        if command == 'funcall':
1574
1707
            funcname = request[1]
1575
1708
            args = request[2]
1576
1709
            kwargs = request[3]
1577
1710
            
1578
 
            parent_pipe.send(('data', getattr(client_object, funcname)(*args, **kwargs)))
1579
 
 
 
1711
            parent_pipe.send(('data', getattr(client_object,
 
1712
                                              funcname)(*args,
 
1713
                                                         **kwargs)))
 
1714
        
1580
1715
        if command == 'getattr':
1581
1716
            attrname = request[1]
1582
1717
            if callable(client_object.__getattribute__(attrname)):
1583
1718
                parent_pipe.send(('function',))
1584
1719
            else:
1585
 
                parent_pipe.send(('data', client_object.__getattribute__(attrname)))
 
1720
                parent_pipe.send(('data', client_object
 
1721
                                  .__getattribute__(attrname)))
1586
1722
        
1587
1723
        if command == 'setattr':
1588
1724
            attrname = request[1]
1589
1725
            value = request[2]
1590
1726
            setattr(client_object, attrname, value)
1591
 
 
 
1727
        
1592
1728
        return True
1593
1729
 
1594
1730
 
1773
1909
    debuglevel = server_settings["debuglevel"]
1774
1910
    use_dbus = server_settings["use_dbus"]
1775
1911
    use_ipv6 = server_settings["use_ipv6"]
1776
 
 
 
1912
    
1777
1913
    if server_settings["servicename"] != "Mandos":
1778
1914
        syslogger.setFormatter(logging.Formatter
1779
1915
                               ('Mandos (%s) [%%(process)d]:'
1840
1976
        level = getattr(logging, debuglevel.upper())
1841
1977
        syslogger.setLevel(level)
1842
1978
        console.setLevel(level)
1843
 
 
 
1979
    
1844
1980
    if debug:
1845
1981
        # Enable all possible GnuTLS debugging
1846
1982
        
1877
2013
    # End of Avahi example code
1878
2014
    if use_dbus:
1879
2015
        try:
1880
 
            bus_name = dbus.service.BusName("se.bsnet.fukt.Mandos",
 
2016
            bus_name = dbus.service.BusName("se.recompile.Mandos",
1881
2017
                                            bus, do_not_queue=True)
 
2018
            old_bus_name = (dbus.service.BusName
 
2019
                            ("se.bsnet.fukt.Mandos", bus,
 
2020
                             do_not_queue=True))
1882
2021
        except dbus.exceptions.NameExistsException as e:
1883
2022
            logger.error(unicode(e) + ", disabling D-Bus")
1884
2023
            use_dbus = False
1897
2036
    
1898
2037
    client_class = Client
1899
2038
    if use_dbus:
1900
 
        client_class = functools.partial(ClientDBus, bus = bus)
 
2039
        client_class = functools.partial(ClientDBusTransitional,
 
2040
                                         bus = bus)
1901
2041
    def client_config_items(config, section):
1902
2042
        special_settings = {
1903
2043
            "approved_by_default":
1933
2073
        del pidfilename
1934
2074
        
1935
2075
        signal.signal(signal.SIGINT, signal.SIG_IGN)
1936
 
 
 
2076
    
1937
2077
    signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
1938
2078
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
1939
2079
    
1942
2082
            """A D-Bus proxy object"""
1943
2083
            def __init__(self):
1944
2084
                dbus.service.Object.__init__(self, bus, "/")
1945
 
            _interface = "se.bsnet.fukt.Mandos"
 
2085
            _interface = "se.recompile.Mandos"
1946
2086
            
1947
2087
            @dbus.service.signal(_interface, signature="o")
1948
2088
            def ClientAdded(self, objpath):
1990
2130
            
1991
2131
            del _interface
1992
2132
        
1993
 
        mandos_dbus_service = MandosDBusService()
 
2133
        class MandosDBusServiceTransitional(MandosDBusService):
 
2134
            __metaclass__ = AlternateDBusNamesMetaclass
 
2135
        mandos_dbus_service = MandosDBusServiceTransitional()
1994
2136
    
1995
2137
    def cleanup():
1996
2138
        "Cleanup function; run on exit"
1997
2139
        service.cleanup()
1998
2140
        
 
2141
        multiprocessing.active_children()
1999
2142
        while tcp_server.clients:
2000
2143
            client = tcp_server.clients.pop()
2001
2144
            if use_dbus:
2005
2148
            client.disable(quiet=True)
2006
2149
            if use_dbus:
2007
2150
                # Emit D-Bus signal
2008
 
                mandos_dbus_service.ClientRemoved(client.dbus_object_path,
 
2151
                mandos_dbus_service.ClientRemoved(client
 
2152
                                                  .dbus_object_path,
2009
2153
                                                  client.name)
2010
2154
    
2011
2155
    atexit.register(cleanup)
2060
2204
    # Must run before the D-Bus bus name gets deregistered
2061
2205
    cleanup()
2062
2206
 
 
2207
 
2063
2208
if __name__ == '__main__':
2064
2209
    main()