230
281
        if config is None:
 
232
283
        logger.debug(u"Creating client %r", self.name)
 
233
 
        self.use_dbus = False   # During __init__
 
234
284
        # Uppercase and remove spaces from fingerprint for later
 
235
285
        # comparison purposes with return value from the fingerprint()
 
237
 
        self.fingerprint = (config["fingerprint"].upper()
 
 
287
        self.fingerprint = (config[u"fingerprint"].upper()
 
238
288
                            .replace(u" ", u""))
 
239
289
        logger.debug(u"  Fingerprint: %s", self.fingerprint)
 
240
 
        if "secret" in config:
 
241
 
            self.secret = config["secret"].decode(u"base64")
 
242
 
        elif "secfile" in config:
 
 
290
        if u"secret" in config:
 
 
291
            self.secret = config[u"secret"].decode(u"base64")
 
 
292
        elif u"secfile" in config:
 
243
293
            with closing(open(os.path.expanduser
 
244
294
                              (os.path.expandvars
 
245
 
                               (config["secfile"])))) as secfile:
 
 
295
                               (config[u"secfile"])),
 
246
297
                self.secret = secfile.read()
 
248
299
            raise TypeError(u"No secret or secfile for client %s"
 
250
 
        self.host = config.get("host", "")
 
 
301
        self.host = config.get(u"host", u"")
 
251
302
        self.created = datetime.datetime.utcnow()
 
252
303
        self.enabled = False
 
253
304
        self.last_enabled = None
 
254
305
        self.last_checked_ok = None
 
255
 
        self.timeout = string_to_delta(config["timeout"])
 
256
 
        self.interval = string_to_delta(config["interval"])
 
 
306
        self.timeout = string_to_delta(config[u"timeout"])
 
 
307
        self.interval = string_to_delta(config[u"interval"])
 
257
308
        self.disable_hook = disable_hook
 
258
309
        self.checker = None
 
259
310
        self.checker_initiator_tag = None
 
260
311
        self.disable_initiator_tag = None
 
261
312
        self.checker_callback_tag = None
 
262
 
        self.checker_command = config["checker"]
 
 
313
        self.checker_command = config[u"checker"]
 
263
314
        self.current_checker_command = None
 
264
315
        self.last_connect = None
 
265
 
        # Only now, when this client is initialized, can it show up on
 
267
 
        self.use_dbus = use_dbus
 
269
 
            self.dbus_object_path = (dbus.ObjectPath
 
271
 
                                      + self.name.replace(".", "_")))
 
272
 
            dbus.service.Object.__init__(self, bus,
 
273
 
                                         self.dbus_object_path)
 
275
317
    def enable(self):
 
276
318
        """Start this client's checker and timeout hooks"""
 
 
319
        if getattr(self, u"enabled", False):
 
277
322
        self.last_enabled = datetime.datetime.utcnow()
 
278
323
        # Schedule a new checker to be started an 'interval' from now,
 
279
324
        # and every interval from then on.
 
280
325
        self.checker_initiator_tag = (gobject.timeout_add
 
281
326
                                      (self.interval_milliseconds(),
 
282
327
                                       self.start_checker))
 
283
 
        # Also start a new checker *right now*.
 
285
328
        # Schedule a disable() when 'timeout' has passed
 
286
329
        self.disable_initiator_tag = (gobject.timeout_add
 
287
330
                                   (self.timeout_milliseconds(),
 
289
332
        self.enabled = True
 
292
 
            self.PropertyChanged(dbus.String(u"enabled"),
 
293
 
                                 dbus.Boolean(True, variant_level=1))
 
294
 
            self.PropertyChanged(dbus.String(u"last_enabled"),
 
295
 
                                 (_datetime_to_dbus(self.last_enabled,
 
 
333
        # Also start a new checker *right now*.
 
 
336
    def disable(self, quiet=True):
 
299
337
        """Disable this client."""
 
300
338
        if not getattr(self, "enabled", False):
 
302
 
        logger.info(u"Disabling client %s", self.name)
 
303
 
        if getattr(self, "disable_initiator_tag", False):
 
 
341
            logger.info(u"Disabling client %s", self.name)
 
 
342
        if getattr(self, u"disable_initiator_tag", False):
 
304
343
            gobject.source_remove(self.disable_initiator_tag)
 
305
344
            self.disable_initiator_tag = None
 
306
 
        if getattr(self, "checker_initiator_tag", False):
 
 
345
        if getattr(self, u"checker_initiator_tag", False):
 
307
346
            gobject.source_remove(self.checker_initiator_tag)
 
308
347
            self.checker_initiator_tag = None
 
309
348
        self.stop_checker()
 
310
349
        if self.disable_hook:
 
311
350
            self.disable_hook(self)
 
312
351
        self.enabled = False
 
315
 
            self.PropertyChanged(dbus.String(u"enabled"),
 
316
 
                                 dbus.Boolean(False, variant_level=1))
 
317
352
        # Do not run this again if called by a gobject.timeout_add
 
 
444
463
        if self.checker_callback_tag:
 
445
464
            gobject.source_remove(self.checker_callback_tag)
 
446
465
            self.checker_callback_tag = None
 
447
 
        if getattr(self, "checker", None) is None:
 
 
466
        if getattr(self, u"checker", None) is None:
 
449
468
        logger.debug(u"Stopping checker for %(name)s", vars(self))
 
451
470
            os.kill(self.checker.pid, signal.SIGTERM)
 
453
472
            #if self.checker.poll() is None:
 
454
473
            #    os.kill(self.checker.pid, signal.SIGKILL)
 
455
474
        except OSError, error:
 
456
475
            if error.errno != errno.ESRCH: # No such process
 
458
477
        self.checker = None
 
460
 
            self.PropertyChanged(dbus.String(u"checker_running"),
 
461
 
                                 dbus.Boolean(False, variant_level=1))
 
463
479
    def still_valid(self):
 
464
480
        """Has the timeout not yet passed for this client?"""
 
465
 
        if not getattr(self, "enabled", False):
 
 
481
        if not getattr(self, u"enabled", False):
 
467
483
        now = datetime.datetime.utcnow()
 
468
484
        if self.last_checked_ok is None:
 
469
485
            return now < (self.created + self.timeout)
 
471
487
            return now < (self.last_checked_ok + self.timeout)
 
 
490
def dbus_service_property(dbus_interface, signature=u"v",
 
 
491
                          access=u"readwrite", byte_arrays=False):
 
 
492
    """Decorators for marking methods of a DBusObjectWithProperties to
 
 
493
    become properties on the D-Bus.
 
 
495
    The decorated method will be called with no arguments by "Get"
 
 
496
    and with one argument by "Set".
 
 
498
    The parameters, where they are supported, are the same as
 
 
499
    dbus.service.method, except there is only "signature", since the
 
 
500
    type from Get() and the type sent to Set() is the same.
 
 
503
        func._dbus_is_property = True
 
 
504
        func._dbus_interface = dbus_interface
 
 
505
        func._dbus_signature = signature
 
 
506
        func._dbus_access = access
 
 
507
        func._dbus_name = func.__name__
 
 
508
        if func._dbus_name.endswith(u"_dbus_property"):
 
 
509
            func._dbus_name = func._dbus_name[:-14]
 
 
510
        func._dbus_get_args_options = {u'byte_arrays': byte_arrays }
 
 
515
class DBusPropertyException(dbus.exceptions.DBusException):
 
 
516
    """A base class for D-Bus property-related exceptions
 
 
518
    def __unicode__(self):
 
 
519
        return unicode(str(self))
 
 
522
class DBusPropertyAccessException(DBusPropertyException):
 
 
523
    """A property's access permissions disallows an operation.
 
 
528
class DBusPropertyNotFound(DBusPropertyException):
 
 
529
    """An attempt was made to access a non-existing property.
 
 
534
class DBusObjectWithProperties(dbus.service.Object):
 
 
535
    """A D-Bus object with properties.
 
 
537
    Classes inheriting from this can use the dbus_service_property
 
 
538
    decorator to expose methods as D-Bus properties.  It exposes the
 
 
539
    standard Get(), Set(), and GetAll() methods on the D-Bus.
 
 
543
    def _is_dbus_property(obj):
 
 
544
        return getattr(obj, u"_dbus_is_property", False)
 
 
546
    def _get_all_dbus_properties(self):
 
 
547
        """Returns a generator of (name, attribute) pairs
 
 
549
        return ((prop._dbus_name, prop)
 
 
551
                inspect.getmembers(self, self._is_dbus_property))
 
 
553
    def _get_dbus_property(self, interface_name, property_name):
 
 
554
        """Returns a bound method if one exists which is a D-Bus
 
 
555
        property with the specified name and interface.
 
 
557
        for name in (property_name,
 
 
558
                     property_name + u"_dbus_property"):
 
 
559
            prop = getattr(self, name, None)
 
 
561
                or not self._is_dbus_property(prop)
 
 
562
                or prop._dbus_name != property_name
 
 
563
                or (interface_name and prop._dbus_interface
 
 
564
                    and interface_name != prop._dbus_interface)):
 
 
568
        raise DBusPropertyNotFound(self.dbus_object_path + u":"
 
 
569
                                   + interface_name + u"."
 
 
572
    @dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ss",
 
 
574
    def Get(self, interface_name, property_name):
 
 
575
        """Standard D-Bus property Get() method, see D-Bus standard.
 
 
577
        prop = self._get_dbus_property(interface_name, property_name)
 
 
578
        if prop._dbus_access == u"write":
 
 
579
            raise DBusPropertyAccessException(property_name)
 
 
581
        if not hasattr(value, u"variant_level"):
 
 
583
        return type(value)(value, variant_level=value.variant_level+1)
 
 
585
    @dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ssv")
 
 
586
    def Set(self, interface_name, property_name, value):
 
 
587
        """Standard D-Bus property Set() method, see D-Bus standard.
 
 
589
        prop = self._get_dbus_property(interface_name, property_name)
 
 
590
        if prop._dbus_access == u"read":
 
 
591
            raise DBusPropertyAccessException(property_name)
 
 
592
        if prop._dbus_get_args_options[u"byte_arrays"]:
 
 
593
            value = dbus.ByteArray(''.join(unichr(byte)
 
 
597
    @dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"s",
 
 
598
                         out_signature=u"a{sv}")
 
 
599
    def GetAll(self, interface_name):
 
 
600
        """Standard D-Bus property GetAll() method, see D-Bus
 
 
603
        Note: Will not include properties with access="write".
 
 
606
        for name, prop in self._get_all_dbus_properties():
 
 
608
                and interface_name != prop._dbus_interface):
 
 
609
                # Interface non-empty but did not match
 
 
611
            # Ignore write-only properties
 
 
612
            if prop._dbus_access == u"write":
 
 
615
            if not hasattr(value, u"variant_level"):
 
 
618
            all[name] = type(value)(value, variant_level=
 
 
619
                                    value.variant_level+1)
 
 
620
        return dbus.Dictionary(all, signature=u"sv")
 
 
622
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
 
 
624
                         path_keyword='object_path',
 
 
625
                         connection_keyword='connection')
 
 
626
    def Introspect(self, object_path, connection):
 
 
627
        """Standard D-Bus method, overloaded to insert property tags.
 
 
629
        xmlstring = dbus.service.Object.Introspect(self, object_path,
 
 
632
            document = xml.dom.minidom.parseString(xmlstring)
 
 
633
            def make_tag(document, name, prop):
 
 
634
                e = document.createElement(u"property")
 
 
635
                e.setAttribute(u"name", name)
 
 
636
                e.setAttribute(u"type", prop._dbus_signature)
 
 
637
                e.setAttribute(u"access", prop._dbus_access)
 
 
639
            for if_tag in document.getElementsByTagName(u"interface"):
 
 
640
                for tag in (make_tag(document, name, prop)
 
 
642
                            in self._get_all_dbus_properties()
 
 
643
                            if prop._dbus_interface
 
 
644
                            == if_tag.getAttribute(u"name")):
 
 
645
                    if_tag.appendChild(tag)
 
 
646
                # Add the names to the return values for the
 
 
647
                # "org.freedesktop.DBus.Properties" methods
 
 
648
                if (if_tag.getAttribute(u"name")
 
 
649
                    == u"org.freedesktop.DBus.Properties"):
 
 
650
                    for cn in if_tag.getElementsByTagName(u"method"):
 
 
651
                        if cn.getAttribute(u"name") == u"Get":
 
 
652
                            for arg in cn.getElementsByTagName(u"arg"):
 
 
653
                                if (arg.getAttribute(u"direction")
 
 
655
                                    arg.setAttribute(u"name", u"value")
 
 
656
                        elif cn.getAttribute(u"name") == u"GetAll":
 
 
657
                            for arg in cn.getElementsByTagName(u"arg"):
 
 
658
                                if (arg.getAttribute(u"direction")
 
 
660
                                    arg.setAttribute(u"name", u"props")
 
 
661
            xmlstring = document.toxml(u"utf-8")
 
 
663
        except (AttributeError, xml.dom.DOMException,
 
 
664
                xml.parsers.expat.ExpatError), error:
 
 
665
            logger.error(u"Failed to override Introspection method",
 
 
670
class ClientDBus(Client, DBusObjectWithProperties):
 
 
671
    """A Client class using D-Bus
 
 
674
    dbus_object_path: dbus.ObjectPath
 
 
675
    bus: dbus.SystemBus()
 
 
677
    # dbus.service.Object doesn't use super(), so we can't either.
 
 
679
    def __init__(self, bus = None, *args, **kwargs):
 
 
681
        Client.__init__(self, *args, **kwargs)
 
 
682
        # Only now, when this client is initialized, can it show up on
 
 
684
        self.dbus_object_path = (dbus.ObjectPath
 
 
686
                                  + self.name.replace(u".", u"_")))
 
 
687
        DBusObjectWithProperties.__init__(self, self.bus,
 
 
688
                                          self.dbus_object_path)
 
 
691
    def _datetime_to_dbus(dt, variant_level=0):
 
 
692
        """Convert a UTC datetime.datetime() to a D-Bus type."""
 
 
693
        return dbus.String(dt.isoformat(),
 
 
694
                           variant_level=variant_level)
 
 
697
        oldstate = getattr(self, u"enabled", False)
 
 
698
        r = Client.enable(self)
 
 
699
        if oldstate != self.enabled:
 
 
701
            self.PropertyChanged(dbus.String(u"enabled"),
 
 
702
                                 dbus.Boolean(True, variant_level=1))
 
 
703
            self.PropertyChanged(
 
 
704
                dbus.String(u"last_enabled"),
 
 
705
                self._datetime_to_dbus(self.last_enabled,
 
 
709
    def disable(self, quiet = False):
 
 
710
        oldstate = getattr(self, u"enabled", False)
 
 
711
        r = Client.disable(self, quiet=quiet)
 
 
712
        if not quiet and oldstate != self.enabled:
 
 
714
            self.PropertyChanged(dbus.String(u"enabled"),
 
 
715
                                 dbus.Boolean(False, variant_level=1))
 
 
718
    def __del__(self, *args, **kwargs):
 
 
720
            self.remove_from_connection()
 
 
723
        if hasattr(DBusObjectWithProperties, u"__del__"):
 
 
724
            DBusObjectWithProperties.__del__(self, *args, **kwargs)
 
 
725
        Client.__del__(self, *args, **kwargs)
 
 
727
    def checker_callback(self, pid, condition, command,
 
 
729
        self.checker_callback_tag = None
 
 
732
        self.PropertyChanged(dbus.String(u"checker_running"),
 
 
733
                             dbus.Boolean(False, variant_level=1))
 
 
734
        if os.WIFEXITED(condition):
 
 
735
            exitstatus = os.WEXITSTATUS(condition)
 
 
737
            self.CheckerCompleted(dbus.Int16(exitstatus),
 
 
738
                                  dbus.Int64(condition),
 
 
739
                                  dbus.String(command))
 
 
742
            self.CheckerCompleted(dbus.Int16(-1),
 
 
743
                                  dbus.Int64(condition),
 
 
744
                                  dbus.String(command))
 
 
746
        return Client.checker_callback(self, pid, condition, command,
 
 
749
    def checked_ok(self, *args, **kwargs):
 
 
750
        r = Client.checked_ok(self, *args, **kwargs)
 
 
752
        self.PropertyChanged(
 
 
753
            dbus.String(u"last_checked_ok"),
 
 
754
            (self._datetime_to_dbus(self.last_checked_ok,
 
 
758
    def start_checker(self, *args, **kwargs):
 
 
759
        old_checker = self.checker
 
 
760
        if self.checker is not None:
 
 
761
            old_checker_pid = self.checker.pid
 
 
763
            old_checker_pid = None
 
 
764
        r = Client.start_checker(self, *args, **kwargs)
 
 
765
        # Only if new checker process was started
 
 
766
        if (self.checker is not None
 
 
767
            and old_checker_pid != self.checker.pid):
 
 
769
            self.CheckerStarted(self.current_checker_command)
 
 
770
            self.PropertyChanged(
 
 
771
                dbus.String(u"checker_running"),
 
 
772
                dbus.Boolean(True, variant_level=1))
 
 
775
    def stop_checker(self, *args, **kwargs):
 
 
776
        old_checker = getattr(self, u"checker", None)
 
 
777
        r = Client.stop_checker(self, *args, **kwargs)
 
 
778
        if (old_checker is not None
 
 
779
            and getattr(self, u"checker", None) is None):
 
 
780
            self.PropertyChanged(dbus.String(u"checker_running"),
 
 
781
                                 dbus.Boolean(False, variant_level=1))
 
473
784
    ## D-Bus methods & signals
 
474
785
    _interface = u"se.bsnet.fukt.Mandos.Client"
 
476
787
    # CheckedOK - method
 
477
 
    CheckedOK = dbus.service.method(_interface)(checked_ok)
 
478
 
    CheckedOK.__name__ = "CheckedOK"
 
 
788
    @dbus.service.method(_interface)
 
 
790
        return self.checked_ok()
 
480
792
    # CheckerCompleted - signal
 
481
 
    @dbus.service.signal(_interface, signature="nxs")
 
 
793
    @dbus.service.signal(_interface, signature=u"nxs")
 
482
794
    def CheckerCompleted(self, exitcode, waitstatus, command):
 
486
798
    # CheckerStarted - signal
 
487
 
    @dbus.service.signal(_interface, signature="s")
 
 
799
    @dbus.service.signal(_interface, signature=u"s")
 
488
800
    def CheckerStarted(self, command):
 
492
 
    # GetAllProperties - method
 
493
 
    @dbus.service.method(_interface, out_signature="a{sv}")
 
494
 
    def GetAllProperties(self):
 
496
 
        return dbus.Dictionary({
 
498
 
                    dbus.String(self.name, variant_level=1),
 
499
 
                dbus.String("fingerprint"):
 
500
 
                    dbus.String(self.fingerprint, variant_level=1),
 
502
 
                    dbus.String(self.host, variant_level=1),
 
503
 
                dbus.String("created"):
 
504
 
                    _datetime_to_dbus(self.created, variant_level=1),
 
505
 
                dbus.String("last_enabled"):
 
506
 
                    (_datetime_to_dbus(self.last_enabled,
 
508
 
                     if self.last_enabled is not None
 
509
 
                     else dbus.Boolean(False, variant_level=1)),
 
510
 
                dbus.String("enabled"):
 
511
 
                    dbus.Boolean(self.enabled, variant_level=1),
 
512
 
                dbus.String("last_checked_ok"):
 
513
 
                    (_datetime_to_dbus(self.last_checked_ok,
 
515
 
                     if self.last_checked_ok is not None
 
516
 
                     else dbus.Boolean (False, variant_level=1)),
 
517
 
                dbus.String("timeout"):
 
518
 
                    dbus.UInt64(self.timeout_milliseconds(),
 
520
 
                dbus.String("interval"):
 
521
 
                    dbus.UInt64(self.interval_milliseconds(),
 
523
 
                dbus.String("checker"):
 
524
 
                    dbus.String(self.checker_command,
 
526
 
                dbus.String("checker_running"):
 
527
 
                    dbus.Boolean(self.checker is not None,
 
529
 
                dbus.String("object_path"):
 
530
 
                    dbus.ObjectPath(self.dbus_object_path,
 
534
 
    # IsStillValid - method
 
535
 
    IsStillValid = (dbus.service.method(_interface, out_signature="b")
 
537
 
    IsStillValid.__name__ = "IsStillValid"
 
539
804
    # PropertyChanged - signal
 
540
 
    @dbus.service.signal(_interface, signature="sv")
 
 
805
    @dbus.service.signal(_interface, signature=u"sv")
 
541
806
    def PropertyChanged(self, property, value):
 
545
 
    # SetChecker - method
 
546
 
    @dbus.service.method(_interface, in_signature="s")
 
547
 
    def SetChecker(self, checker):
 
548
 
        "D-Bus setter method"
 
549
 
        self.checker_command = checker
 
551
 
        self.PropertyChanged(dbus.String(u"checker"),
 
552
 
                             dbus.String(self.checker_command,
 
556
 
    @dbus.service.method(_interface, in_signature="s")
 
557
 
    def SetHost(self, host):
 
558
 
        "D-Bus setter method"
 
561
 
        self.PropertyChanged(dbus.String(u"host"),
 
562
 
                             dbus.String(self.host, variant_level=1))
 
564
 
    # SetInterval - method
 
565
 
    @dbus.service.method(_interface, in_signature="t")
 
566
 
    def SetInterval(self, milliseconds):
 
567
 
        self.interval = datetime.timedelta(0, 0, 0, milliseconds)
 
569
 
        self.PropertyChanged(dbus.String(u"interval"),
 
570
 
                             (dbus.UInt64(self.interval_milliseconds(),
 
574
 
    @dbus.service.method(_interface, in_signature="ay",
 
576
 
    def SetSecret(self, secret):
 
577
 
        "D-Bus setter method"
 
578
 
        self.secret = str(secret)
 
580
 
    # SetTimeout - method
 
581
 
    @dbus.service.method(_interface, in_signature="t")
 
582
 
    def SetTimeout(self, milliseconds):
 
583
 
        self.timeout = datetime.timedelta(0, 0, 0, milliseconds)
 
585
 
        self.PropertyChanged(dbus.String(u"timeout"),
 
586
 
                             (dbus.UInt64(self.timeout_milliseconds(),
 
 
811
    @dbus.service.signal(_interface)
 
 
817
    @dbus.service.signal(_interface)
 
589
822
    # Enable - method
 
590
 
    Enable = dbus.service.method(_interface)(enable)
 
591
 
    Enable.__name__ = "Enable"
 
 
823
    @dbus.service.method(_interface)
 
593
828
    # StartChecker - method
 
594
829
    @dbus.service.method(_interface)
 
 
605
840
    # StopChecker - method
 
606
 
    StopChecker = dbus.service.method(_interface)(stop_checker)
 
607
 
    StopChecker.__name__ = "StopChecker"
 
 
841
    @dbus.service.method(_interface)
 
 
842
    def StopChecker(self):
 
 
846
    @dbus_service_property(_interface, signature=u"s", access=u"read")
 
 
847
    def name_dbus_property(self):
 
 
848
        return dbus.String(self.name)
 
 
850
    # fingerprint - property
 
 
851
    @dbus_service_property(_interface, signature=u"s", access=u"read")
 
 
852
    def fingerprint_dbus_property(self):
 
 
853
        return dbus.String(self.fingerprint)
 
 
856
    @dbus_service_property(_interface, signature=u"s",
 
 
858
    def host_dbus_property(self, value=None):
 
 
859
        if value is None:       # get
 
 
860
            return dbus.String(self.host)
 
 
863
        self.PropertyChanged(dbus.String(u"host"),
 
 
864
                             dbus.String(value, variant_level=1))
 
 
867
    @dbus_service_property(_interface, signature=u"s", access=u"read")
 
 
868
    def created_dbus_property(self):
 
 
869
        return dbus.String(self._datetime_to_dbus(self.created))
 
 
871
    # last_enabled - property
 
 
872
    @dbus_service_property(_interface, signature=u"s", access=u"read")
 
 
873
    def last_enabled_dbus_property(self):
 
 
874
        if self.last_enabled is None:
 
 
875
            return dbus.String(u"")
 
 
876
        return dbus.String(self._datetime_to_dbus(self.last_enabled))
 
 
879
    @dbus_service_property(_interface, signature=u"b",
 
 
881
    def enabled_dbus_property(self, value=None):
 
 
882
        if value is None:       # get
 
 
883
            return dbus.Boolean(self.enabled)
 
 
889
    # last_checked_ok - property
 
 
890
    @dbus_service_property(_interface, signature=u"s",
 
 
892
    def last_checked_ok_dbus_property(self, value=None):
 
 
893
        if value is not None:
 
 
896
        if self.last_checked_ok is None:
 
 
897
            return dbus.String(u"")
 
 
898
        return dbus.String(self._datetime_to_dbus(self
 
 
902
    @dbus_service_property(_interface, signature=u"t",
 
 
904
    def timeout_dbus_property(self, value=None):
 
 
905
        if value is None:       # get
 
 
906
            return dbus.UInt64(self.timeout_milliseconds())
 
 
907
        self.timeout = datetime.timedelta(0, 0, 0, value)
 
 
909
        self.PropertyChanged(dbus.String(u"timeout"),
 
 
910
                             dbus.UInt64(value, variant_level=1))
 
 
911
        if getattr(self, u"disable_initiator_tag", None) is None:
 
 
914
        gobject.source_remove(self.disable_initiator_tag)
 
 
915
        self.disable_initiator_tag = None
 
 
917
                       _timedelta_to_milliseconds((self
 
 
923
            # The timeout has passed
 
 
926
            self.disable_initiator_tag = (gobject.timeout_add
 
 
927
                                          (time_to_die, self.disable))
 
 
929
    # interval - property
 
 
930
    @dbus_service_property(_interface, signature=u"t",
 
 
932
    def interval_dbus_property(self, value=None):
 
 
933
        if value is None:       # get
 
 
934
            return dbus.UInt64(self.interval_milliseconds())
 
 
935
        self.interval = datetime.timedelta(0, 0, 0, value)
 
 
937
        self.PropertyChanged(dbus.String(u"interval"),
 
 
938
                             dbus.UInt64(value, variant_level=1))
 
 
939
        if getattr(self, u"checker_initiator_tag", None) is None:
 
 
941
        # Reschedule checker run
 
 
942
        gobject.source_remove(self.checker_initiator_tag)
 
 
943
        self.checker_initiator_tag = (gobject.timeout_add
 
 
944
                                      (value, self.start_checker))
 
 
945
        self.start_checker()    # Start one now, too
 
 
948
    @dbus_service_property(_interface, signature=u"s",
 
 
950
    def checker_dbus_property(self, value=None):
 
 
951
        if value is None:       # get
 
 
952
            return dbus.String(self.checker_command)
 
 
953
        self.checker_command = value
 
 
955
        self.PropertyChanged(dbus.String(u"checker"),
 
 
956
                             dbus.String(self.checker_command,
 
 
959
    # checker_running - property
 
 
960
    @dbus_service_property(_interface, signature=u"b",
 
 
962
    def checker_running_dbus_property(self, value=None):
 
 
963
        if value is None:       # get
 
 
964
            return dbus.Boolean(self.checker is not None)
 
 
970
    # object_path - property
 
 
971
    @dbus_service_property(_interface, signature=u"o", access=u"read")
 
 
972
    def object_path_dbus_property(self):
 
 
973
        return self.dbus_object_path # is already a dbus.ObjectPath
 
 
976
    @dbus_service_property(_interface, signature=u"ay",
 
 
977
                           access=u"write", byte_arrays=True)
 
 
978
    def secret_dbus_property(self, value):
 
 
979
        self.secret = str(value)
 
612
 
def peer_certificate(session):
 
613
 
    "Return the peer's OpenPGP certificate as a bytestring"
 
614
 
    # If not an OpenPGP certificate...
 
615
 
    if (gnutls.library.functions
 
616
 
        .gnutls_certificate_type_get(session._c_object)
 
617
 
        != gnutls.library.constants.GNUTLS_CRT_OPENPGP):
 
618
 
        # ...do the normal thing
 
619
 
        return session.peer_certificate
 
620
 
    list_size = ctypes.c_uint(1)
 
621
 
    cert_list = (gnutls.library.functions
 
622
 
                 .gnutls_certificate_get_peers
 
623
 
                 (session._c_object, ctypes.byref(list_size)))
 
624
 
    if not bool(cert_list) and list_size.value != 0:
 
625
 
        raise gnutls.errors.GNUTLSError("error getting peer"
 
627
 
    if list_size.value == 0:
 
630
 
    return ctypes.string_at(cert.data, cert.size)
 
633
 
def fingerprint(openpgp):
 
634
 
    "Convert an OpenPGP bytestring to a hexdigit fingerprint string"
 
635
 
    # New GnuTLS "datum" with the OpenPGP public key
 
636
 
    datum = (gnutls.library.types
 
637
 
             .gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp),
 
640
 
                             ctypes.c_uint(len(openpgp))))
 
641
 
    # New empty GnuTLS certificate
 
642
 
    crt = gnutls.library.types.gnutls_openpgp_crt_t()
 
643
 
    (gnutls.library.functions
 
644
 
     .gnutls_openpgp_crt_init(ctypes.byref(crt)))
 
645
 
    # Import the OpenPGP public key into the certificate
 
646
 
    (gnutls.library.functions
 
647
 
     .gnutls_openpgp_crt_import(crt, ctypes.byref(datum),
 
648
 
                                gnutls.library.constants
 
649
 
                                .GNUTLS_OPENPGP_FMT_RAW))
 
650
 
    # Verify the self signature in the key
 
651
 
    crtverify = ctypes.c_uint()
 
652
 
    (gnutls.library.functions
 
653
 
     .gnutls_openpgp_crt_verify_self(crt, 0, ctypes.byref(crtverify)))
 
654
 
    if crtverify.value != 0:
 
655
 
        gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
 
656
 
        raise gnutls.errors.CertificateSecurityError("Verify failed")
 
657
 
    # New buffer for the fingerprint
 
658
 
    buf = ctypes.create_string_buffer(20)
 
659
 
    buf_len = ctypes.c_size_t()
 
660
 
    # Get the fingerprint from the certificate into the buffer
 
661
 
    (gnutls.library.functions
 
662
 
     .gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
 
663
 
                                         ctypes.byref(buf_len)))
 
664
 
    # Deinit the certificate
 
665
 
    gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
 
666
 
    # Convert the buffer to a Python bytestring
 
667
 
    fpr = ctypes.string_at(buf, buf_len.value)
 
668
 
    # Convert the bytestring to hexadecimal notation
 
669
 
    hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
 
673
 
class TCP_handler(SocketServer.BaseRequestHandler, object):
 
674
 
    """A TCP request handler class.
 
675
 
    Instantiated by IPv6_TCPServer for each request to handle it.
 
 
984
class ClientHandler(socketserver.BaseRequestHandler, object):
 
 
985
    """A class to handle client connections.
 
 
987
    Instantiated once for each connection to handle it.
 
676
988
    Note: This will run in its own forked process."""
 
678
990
    def handle(self):
 
679
991
        logger.info(u"TCP connection from: %s",
 
680
992
                    unicode(self.client_address))
 
681
 
        session = (gnutls.connection
 
682
 
                   .ClientSession(self.request,
 
686
 
        line = self.request.makefile().readline()
 
687
 
        logger.debug(u"Protocol version: %r", line)
 
689
 
            if int(line.strip().split()[0]) > 1:
 
691
 
        except (ValueError, IndexError, RuntimeError), error:
 
692
 
            logger.error(u"Unknown protocol version: %s", error)
 
695
 
        # Note: gnutls.connection.X509Credentials is really a generic
 
696
 
        # GnuTLS certificate credentials object so long as no X.509
 
697
 
        # keys are added to it.  Therefore, we can use it here despite
 
698
 
        # using OpenPGP certificates.
 
700
 
        #priority = ':'.join(("NONE", "+VERS-TLS1.1", "+AES-256-CBC",
 
701
 
        #                     "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP",
 
703
 
        # Use a fallback default, since this MUST be set.
 
704
 
        priority = self.server.settings.get("priority", "NORMAL")
 
705
 
        (gnutls.library.functions
 
706
 
         .gnutls_priority_set_direct(session._c_object,
 
711
 
        except gnutls.errors.GNUTLSError, error:
 
712
 
            logger.warning(u"Handshake failed: %s", error)
 
713
 
            # Do not run session.bye() here: the session is not
 
714
 
            # established.  Just abandon the request.
 
716
 
        logger.debug(u"Handshake succeeded")
 
718
 
            fpr = fingerprint(peer_certificate(session))
 
719
 
        except (TypeError, gnutls.errors.GNUTLSError), error:
 
720
 
            logger.warning(u"Bad certificate: %s", error)
 
723
 
        logger.debug(u"Fingerprint: %s", fpr)
 
725
 
        for c in self.server.clients:
 
726
 
            if c.fingerprint == fpr:
 
730
 
            logger.warning(u"Client not found for fingerprint: %s",
 
734
 
        # Have to check if client.still_valid(), since it is possible
 
735
 
        # that the client timed out while establishing the GnuTLS
 
737
 
        if not client.still_valid():
 
738
 
            logger.warning(u"Client %(name)s is invalid",
 
742
 
        ## This won't work here, since we're in a fork.
 
743
 
        # client.checked_ok()
 
745
 
        while sent_size < len(client.secret):
 
746
 
            sent = session.send(client.secret[sent_size:])
 
747
 
            logger.debug(u"Sent: %d, remaining: %d",
 
748
 
                         sent, len(client.secret)
 
749
 
                         - (sent_size + sent))
 
754
 
class IPv6_TCPServer(SocketServer.ForkingMixIn,
 
755
 
                     SocketServer.TCPServer, object):
 
 
993
        logger.debug(u"IPC Pipe FD: %d", self.server.pipe[1])
 
 
994
        # Open IPC pipe to parent process
 
 
995
        with closing(os.fdopen(self.server.pipe[1], u"w", 1)) as ipc:
 
 
996
            session = (gnutls.connection
 
 
997
                       .ClientSession(self.request,
 
 
1001
            line = self.request.makefile().readline()
 
 
1002
            logger.debug(u"Protocol version: %r", line)
 
 
1004
                if int(line.strip().split()[0]) > 1:
 
 
1006
            except (ValueError, IndexError, RuntimeError), error:
 
 
1007
                logger.error(u"Unknown protocol version: %s", error)
 
 
1010
            # Note: gnutls.connection.X509Credentials is really a
 
 
1011
            # generic GnuTLS certificate credentials object so long as
 
 
1012
            # no X.509 keys are added to it.  Therefore, we can use it
 
 
1013
            # here despite using OpenPGP certificates.
 
 
1015
            #priority = u':'.join((u"NONE", u"+VERS-TLS1.1",
 
 
1016
            #                      u"+AES-256-CBC", u"+SHA1",
 
 
1017
            #                      u"+COMP-NULL", u"+CTYPE-OPENPGP",
 
 
1019
            # Use a fallback default, since this MUST be set.
 
 
1020
            priority = self.server.gnutls_priority
 
 
1021
            if priority is None:
 
 
1022
                priority = u"NORMAL"
 
 
1023
            (gnutls.library.functions
 
 
1024
             .gnutls_priority_set_direct(session._c_object,
 
 
1029
            except gnutls.errors.GNUTLSError, error:
 
 
1030
                logger.warning(u"Handshake failed: %s", error)
 
 
1031
                # Do not run session.bye() here: the session is not
 
 
1032
                # established.  Just abandon the request.
 
 
1034
            logger.debug(u"Handshake succeeded")
 
 
1036
                fpr = self.fingerprint(self.peer_certificate(session))
 
 
1037
            except (TypeError, gnutls.errors.GNUTLSError), error:
 
 
1038
                logger.warning(u"Bad certificate: %s", error)
 
 
1041
            logger.debug(u"Fingerprint: %s", fpr)
 
 
1043
            for c in self.server.clients:
 
 
1044
                if c.fingerprint == fpr:
 
 
1048
                ipc.write(u"NOTFOUND %s %s\n"
 
 
1049
                          % (fpr, unicode(self.client_address)))
 
 
1052
            # Have to check if client.still_valid(), since it is
 
 
1053
            # possible that the client timed out while establishing
 
 
1054
            # the GnuTLS session.
 
 
1055
            if not client.still_valid():
 
 
1056
                ipc.write(u"INVALID %s\n" % client.name)
 
 
1059
            ipc.write(u"SENDING %s\n" % client.name)
 
 
1061
            while sent_size < len(client.secret):
 
 
1062
                sent = session.send(client.secret[sent_size:])
 
 
1063
                logger.debug(u"Sent: %d, remaining: %d",
 
 
1064
                             sent, len(client.secret)
 
 
1065
                             - (sent_size + sent))
 
 
1070
    def peer_certificate(session):
 
 
1071
        "Return the peer's OpenPGP certificate as a bytestring"
 
 
1072
        # If not an OpenPGP certificate...
 
 
1073
        if (gnutls.library.functions
 
 
1074
            .gnutls_certificate_type_get(session._c_object)
 
 
1075
            != gnutls.library.constants.GNUTLS_CRT_OPENPGP):
 
 
1076
            # ...do the normal thing
 
 
1077
            return session.peer_certificate
 
 
1078
        list_size = ctypes.c_uint(1)
 
 
1079
        cert_list = (gnutls.library.functions
 
 
1080
                     .gnutls_certificate_get_peers
 
 
1081
                     (session._c_object, ctypes.byref(list_size)))
 
 
1082
        if not bool(cert_list) and list_size.value != 0:
 
 
1083
            raise gnutls.errors.GNUTLSError(u"error getting peer"
 
 
1085
        if list_size.value == 0:
 
 
1088
        return ctypes.string_at(cert.data, cert.size)
 
 
1091
    def fingerprint(openpgp):
 
 
1092
        "Convert an OpenPGP bytestring to a hexdigit fingerprint"
 
 
1093
        # New GnuTLS "datum" with the OpenPGP public key
 
 
1094
        datum = (gnutls.library.types
 
 
1095
                 .gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp),
 
 
1098
                                 ctypes.c_uint(len(openpgp))))
 
 
1099
        # New empty GnuTLS certificate
 
 
1100
        crt = gnutls.library.types.gnutls_openpgp_crt_t()
 
 
1101
        (gnutls.library.functions
 
 
1102
         .gnutls_openpgp_crt_init(ctypes.byref(crt)))
 
 
1103
        # Import the OpenPGP public key into the certificate
 
 
1104
        (gnutls.library.functions
 
 
1105
         .gnutls_openpgp_crt_import(crt, ctypes.byref(datum),
 
 
1106
                                    gnutls.library.constants
 
 
1107
                                    .GNUTLS_OPENPGP_FMT_RAW))
 
 
1108
        # Verify the self signature in the key
 
 
1109
        crtverify = ctypes.c_uint()
 
 
1110
        (gnutls.library.functions
 
 
1111
         .gnutls_openpgp_crt_verify_self(crt, 0,
 
 
1112
                                         ctypes.byref(crtverify)))
 
 
1113
        if crtverify.value != 0:
 
 
1114
            gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
 
 
1115
            raise (gnutls.errors.CertificateSecurityError
 
 
1117
        # New buffer for the fingerprint
 
 
1118
        buf = ctypes.create_string_buffer(20)
 
 
1119
        buf_len = ctypes.c_size_t()
 
 
1120
        # Get the fingerprint from the certificate into the buffer
 
 
1121
        (gnutls.library.functions
 
 
1122
         .gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
 
 
1123
                                             ctypes.byref(buf_len)))
 
 
1124
        # Deinit the certificate
 
 
1125
        gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
 
 
1126
        # Convert the buffer to a Python bytestring
 
 
1127
        fpr = ctypes.string_at(buf, buf_len.value)
 
 
1128
        # Convert the bytestring to hexadecimal notation
 
 
1129
        hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
 
 
1133
class ForkingMixInWithPipe(socketserver.ForkingMixIn, object):
 
 
1134
    """Like socketserver.ForkingMixIn, but also pass a pipe."""
 
 
1135
    def process_request(self, request, client_address):
 
 
1136
        """Overrides and wraps the original process_request().
 
 
1138
        This function creates a new pipe in self.pipe
 
 
1140
        self.pipe = os.pipe()
 
 
1141
        super(ForkingMixInWithPipe,
 
 
1142
              self).process_request(request, client_address)
 
 
1143
        os.close(self.pipe[1])  # close write end
 
 
1144
        self.add_pipe(self.pipe[0])
 
 
1145
    def add_pipe(self, pipe):
 
 
1146
        """Dummy function; override as necessary"""
 
 
1150
class IPv6_TCPServer(ForkingMixInWithPipe,
 
 
1151
                     socketserver.TCPServer, object):
 
756
1152
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
 
758
 
        settings:       Server settings
 
759
 
        clients:        Set() of Client objects
 
760
1155
        enabled:        Boolean; whether this server is activated yet
 
 
1156
        interface:      None or a network interface name (string)
 
 
1157
        use_ipv6:       Boolean; to use IPv6 or not
 
762
 
    address_family = socket.AF_INET6
 
763
 
    def __init__(self, *args, **kwargs):
 
764
 
        if "settings" in kwargs:
 
765
 
            self.settings = kwargs["settings"]
 
766
 
            del kwargs["settings"]
 
767
 
        if "clients" in kwargs:
 
768
 
            self.clients = kwargs["clients"]
 
769
 
            del kwargs["clients"]
 
770
 
        if "use_ipv6" in kwargs:
 
771
 
            if not kwargs["use_ipv6"]:
 
772
 
                self.address_family = socket.AF_INET
 
773
 
            del kwargs["use_ipv6"]
 
775
 
        super(IPv6_TCPServer, self).__init__(*args, **kwargs)
 
 
1159
    def __init__(self, server_address, RequestHandlerClass,
 
 
1160
                 interface=None, use_ipv6=True):
 
 
1161
        self.interface = interface
 
 
1163
            self.address_family = socket.AF_INET6
 
 
1164
        socketserver.TCPServer.__init__(self, server_address,
 
 
1165
                                        RequestHandlerClass)
 
776
1166
    def server_bind(self):
 
777
1167
        """This overrides the normal server_bind() function
 
778
1168
        to bind to an interface if one was specified, and also NOT to
 
779
1169
        bind to an address or port if they were not specified."""
 
780
 
        if self.settings["interface"]:
 
781
 
            # 25 is from /usr/include/asm-i486/socket.h
 
782
 
            SO_BINDTODEVICE = getattr(socket, "SO_BINDTODEVICE", 25)
 
784
 
                self.socket.setsockopt(socket.SOL_SOCKET,
 
786
 
                                       self.settings["interface"])
 
787
 
            except socket.error, error:
 
788
 
                if error[0] == errno.EPERM:
 
789
 
                    logger.error(u"No permission to"
 
790
 
                                 u" bind to interface %s",
 
791
 
                                 self.settings["interface"])
 
 
1170
        if self.interface is not None:
 
 
1171
            if SO_BINDTODEVICE is None:
 
 
1172
                logger.error(u"SO_BINDTODEVICE does not exist;"
 
 
1173
                             u" cannot bind to interface %s",
 
 
1177
                    self.socket.setsockopt(socket.SOL_SOCKET,
 
 
1181
                except socket.error, error:
 
 
1182
                    if error[0] == errno.EPERM:
 
 
1183
                        logger.error(u"No permission to"
 
 
1184
                                     u" bind to interface %s",
 
 
1186
                    elif error[0] == errno.ENOPROTOOPT:
 
 
1187
                        logger.error(u"SO_BINDTODEVICE not available;"
 
 
1188
                                     u" cannot bind to interface %s",
 
794
1192
        # Only bind(2) the socket if we really need to.
 
795
1193
        if self.server_address[0] or self.server_address[1]:
 
796
1194
            if not self.server_address[0]:
 
797
1195
                if self.address_family == socket.AF_INET6:
 
798
 
                    any_address = "::" # in6addr_any
 
 
1196
                    any_address = u"::" # in6addr_any
 
800
1198
                    any_address = socket.INADDR_ANY
 
801
1199
                self.server_address = (any_address,
 
 
803
1201
            elif not self.server_address[1]:
 
804
1202
                self.server_address = (self.server_address[0],
 
806
 
#                 if self.settings["interface"]:
 
 
1204
#                 if self.interface:
 
807
1205
#                     self.server_address = (self.server_address[0],
 
810
1208
#                                            if_nametoindex
 
813
 
            return super(IPv6_TCPServer, self).server_bind()
 
 
1210
            return socketserver.TCPServer.server_bind(self)
 
 
1213
class MandosServer(IPv6_TCPServer):
 
 
1217
        clients:        set of Client objects
 
 
1218
        gnutls_priority GnuTLS priority string
 
 
1219
        use_dbus:       Boolean; to emit D-Bus signals or not
 
 
1221
    Assumes a gobject.MainLoop event loop.
 
 
1223
    def __init__(self, server_address, RequestHandlerClass,
 
 
1224
                 interface=None, use_ipv6=True, clients=None,
 
 
1225
                 gnutls_priority=None, use_dbus=True):
 
 
1226
        self.enabled = False
 
 
1227
        self.clients = clients
 
 
1228
        if self.clients is None:
 
 
1229
            self.clients = set()
 
 
1230
        self.use_dbus = use_dbus
 
 
1231
        self.gnutls_priority = gnutls_priority
 
 
1232
        IPv6_TCPServer.__init__(self, server_address,
 
 
1233
                                RequestHandlerClass,
 
 
1234
                                interface = interface,
 
 
1235
                                use_ipv6 = use_ipv6)
 
814
1236
    def server_activate(self):
 
815
1237
        if self.enabled:
 
816
 
            return super(IPv6_TCPServer, self).server_activate()
 
 
1238
            return socketserver.TCPServer.server_activate(self)
 
817
1239
    def enable(self):
 
818
1240
        self.enabled = True
 
 
1241
    def add_pipe(self, pipe):
 
 
1242
        # Call "handle_ipc" for both data and EOF events
 
 
1243
        gobject.io_add_watch(pipe, gobject.IO_IN | gobject.IO_HUP,
 
 
1245
    def handle_ipc(self, source, condition, file_objects={}):
 
 
1247
            gobject.IO_IN: u"IN",   # There is data to read.
 
 
1248
            gobject.IO_OUT: u"OUT", # Data can be written (without
 
 
1250
            gobject.IO_PRI: u"PRI", # There is urgent data to read.
 
 
1251
            gobject.IO_ERR: u"ERR", # Error condition.
 
 
1252
            gobject.IO_HUP: u"HUP"  # Hung up (the connection has been
 
 
1253
                                    # broken, usually for pipes and
 
 
1256
        conditions_string = ' | '.join(name
 
 
1258
                                       condition_names.iteritems()
 
 
1259
                                       if cond & condition)
 
 
1260
        logger.debug(u"Handling IPC: FD = %d, condition = %s", source,
 
 
1263
        # Turn the pipe file descriptor into a Python file object
 
 
1264
        if source not in file_objects:
 
 
1265
            file_objects[source] = os.fdopen(source, u"r", 1)
 
 
1267
        # Read a line from the file object
 
 
1268
        cmdline = file_objects[source].readline()
 
 
1269
        if not cmdline:             # Empty line means end of file
 
 
1270
            # close the IPC pipe
 
 
1271
            file_objects[source].close()
 
 
1272
            del file_objects[source]
 
 
1274
            # Stop calling this function
 
 
1277
        logger.debug(u"IPC command: %r", cmdline)
 
 
1279
        # Parse and act on command
 
 
1280
        cmd, args = cmdline.rstrip(u"\r\n").split(None, 1)
 
 
1282
        if cmd == u"NOTFOUND":
 
 
1283
            fpr, address = args.split(None, 1)
 
 
1284
            logger.warning(u"Client not found for fingerprint: %s, ad"
 
 
1285
                           u"dress: %s", fpr, address)
 
 
1288
                mandos_dbus_service.ClientNotFound(fpr, address)
 
 
1289
        elif cmd == u"INVALID":
 
 
1290
            for client in self.clients:
 
 
1291
                if client.name == args:
 
 
1292
                    logger.warning(u"Client %s is invalid", args)
 
 
1298
                logger.error(u"Unknown client %s is invalid", args)
 
 
1299
        elif cmd == u"SENDING":
 
 
1300
            for client in self.clients:
 
 
1301
                if client.name == args:
 
 
1302
                    logger.info(u"Sending secret to %s", client.name)
 
 
1309
                logger.error(u"Sending secret to unknown client %s",
 
 
1312
            logger.error(u"Unknown IPC command: %r", cmdline)
 
 
1314
        # Keep calling this function
 
821
1318
def string_to_delta(interval):
 
822
1319
    """Parse a string and return a datetime.timedelta
 
824
 
    >>> string_to_delta('7d')
 
 
1321
    >>> string_to_delta(u'7d')
 
825
1322
    datetime.timedelta(7)
 
826
 
    >>> string_to_delta('60s')
 
 
1323
    >>> string_to_delta(u'60s')
 
827
1324
    datetime.timedelta(0, 60)
 
828
 
    >>> string_to_delta('60m')
 
 
1325
    >>> string_to_delta(u'60m')
 
829
1326
    datetime.timedelta(0, 3600)
 
830
 
    >>> string_to_delta('24h')
 
 
1327
    >>> string_to_delta(u'24h')
 
831
1328
    datetime.timedelta(1)
 
832
1329
    >>> string_to_delta(u'1w')
 
833
1330
    datetime.timedelta(7)
 
834
 
    >>> string_to_delta('5m 30s')
 
 
1331
    >>> string_to_delta(u'5m 30s')
 
835
1332
    datetime.timedelta(0, 330)
 
837
1334
    timevalue = datetime.timedelta(0)
 
 
963
1443
    # Default values for config file for server-global settings
 
964
 
    server_defaults = { "interface": "",
 
969
 
                        "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
 
970
 
                        "servicename": "Mandos",
 
 
1444
    server_defaults = { u"interface": u"",
 
 
1449
                        u"SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
 
 
1450
                        u"servicename": u"Mandos",
 
 
1451
                        u"use_dbus": u"True",
 
 
1452
                        u"use_ipv6": u"True",
 
975
1455
    # Parse config file for server-global settings
 
976
 
    server_config = ConfigParser.SafeConfigParser(server_defaults)
 
 
1456
    server_config = configparser.SafeConfigParser(server_defaults)
 
977
1457
    del server_defaults
 
978
 
    server_config.read(os.path.join(options.configdir, "mandos.conf"))
 
 
1458
    server_config.read(os.path.join(options.configdir,
 
979
1460
    # Convert the SafeConfigParser object to a dict
 
980
1461
    server_settings = server_config.defaults()
 
981
1462
    # Use the appropriate methods on the non-string config options
 
982
 
    server_settings["debug"] = server_config.getboolean("DEFAULT",
 
984
 
    server_settings["use_dbus"] = server_config.getboolean("DEFAULT",
 
986
 
    server_settings["use_ipv6"] = server_config.getboolean("DEFAULT",
 
 
1463
    for option in (u"debug", u"use_dbus", u"use_ipv6"):
 
 
1464
        server_settings[option] = server_config.getboolean(u"DEFAULT",
 
988
1466
    if server_settings["port"]:
 
989
 
        server_settings["port"] = server_config.getint("DEFAULT",
 
 
1467
        server_settings["port"] = server_config.getint(u"DEFAULT",
 
991
1469
    del server_config
 
993
1471
    # Override the settings from the config file with command line
 
994
1472
    # options, if set.
 
995
 
    for option in ("interface", "address", "port", "debug",
 
996
 
                   "priority", "servicename", "configdir",
 
997
 
                   "use_dbus", "use_ipv6"):
 
 
1473
    for option in (u"interface", u"address", u"port", u"debug",
 
 
1474
                   u"priority", u"servicename", u"configdir",
 
 
1475
                   u"use_dbus", u"use_ipv6"):
 
998
1476
        value = getattr(options, option)
 
999
1477
        if value is not None:
 
1000
1478
            server_settings[option] = value
 
 
1480
    # Force all strings to be unicode
 
 
1481
    for option in server_settings.keys():
 
 
1482
        if type(server_settings[option]) is str:
 
 
1483
            server_settings[option] = unicode(server_settings[option])
 
1002
1484
    # Now we have our good server settings in "server_settings"
 
 
1486
    ##################################################################
 
1004
1488
    # For convenience
 
1005
 
    debug = server_settings["debug"]
 
1006
 
    use_dbus = server_settings["use_dbus"]
 
1007
 
    use_ipv6 = server_settings["use_ipv6"]
 
 
1489
    debug = server_settings[u"debug"]
 
 
1490
    use_dbus = server_settings[u"use_dbus"]
 
 
1491
    use_ipv6 = server_settings[u"use_ipv6"]
 
1010
1494
        syslogger.setLevel(logging.WARNING)
 
1011
1495
        console.setLevel(logging.WARNING)
 
1013
 
    if server_settings["servicename"] != "Mandos":
 
 
1497
    if server_settings[u"servicename"] != u"Mandos":
 
1014
1498
        syslogger.setFormatter(logging.Formatter
 
1015
 
                               ('Mandos (%s): %%(levelname)s:'
 
1017
 
                                % server_settings["servicename"]))
 
 
1499
                               (u'Mandos (%s) [%%(process)d]:'
 
 
1500
                                u' %%(levelname)s: %%(message)s'
 
 
1501
                                % server_settings[u"servicename"]))
 
1019
1503
    # Parse config file with clients
 
1020
 
    client_defaults = { "timeout": "1h",
 
1022
 
                        "checker": "fping -q -- %%(host)s",
 
 
1504
    client_defaults = { u"timeout": u"1h",
 
 
1506
                        u"checker": u"fping -q -- %%(host)s",
 
1025
 
    client_config = ConfigParser.SafeConfigParser(client_defaults)
 
1026
 
    client_config.read(os.path.join(server_settings["configdir"],
 
1030
 
    tcp_server = IPv6_TCPServer((server_settings["address"],
 
1031
 
                                 server_settings["port"]),
 
1033
 
                                settings=server_settings,
 
1034
 
                                clients=clients, use_ipv6=use_ipv6)
 
1035
 
    pidfilename = "/var/run/mandos.pid"
 
 
1509
    client_config = configparser.SafeConfigParser(client_defaults)
 
 
1510
    client_config.read(os.path.join(server_settings[u"configdir"],
 
 
1513
    global mandos_dbus_service
 
 
1514
    mandos_dbus_service = None
 
 
1516
    tcp_server = MandosServer((server_settings[u"address"],
 
 
1517
                               server_settings[u"port"]),
 
 
1519
                              interface=server_settings[u"interface"],
 
 
1522
                              server_settings[u"priority"],
 
 
1524
    pidfilename = u"/var/run/mandos.pid"
 
1037
 
        pidfile = open(pidfilename, "w")
 
 
1526
        pidfile = open(pidfilename, u"w")
 
1038
1527
    except IOError:
 
1039
 
        logger.error("Could not open file %r", pidfilename)
 
 
1528
        logger.error(u"Could not open file %r", pidfilename)
 
1042
 
        uid = pwd.getpwnam("_mandos").pw_uid
 
1043
 
        gid = pwd.getpwnam("_mandos").pw_gid
 
 
1531
        uid = pwd.getpwnam(u"_mandos").pw_uid
 
 
1532
        gid = pwd.getpwnam(u"_mandos").pw_gid
 
1044
1533
    except KeyError:
 
1046
 
            uid = pwd.getpwnam("mandos").pw_uid
 
1047
 
            gid = pwd.getpwnam("mandos").pw_gid
 
 
1535
            uid = pwd.getpwnam(u"mandos").pw_uid
 
 
1536
            gid = pwd.getpwnam(u"mandos").pw_gid
 
1048
1537
        except KeyError:
 
1050
 
                uid = pwd.getpwnam("nobody").pw_uid
 
1051
 
                gid = pwd.getpwnam("nogroup").pw_gid
 
 
1539
                uid = pwd.getpwnam(u"nobody").pw_uid
 
 
1540
                gid = pwd.getpwnam(u"nobody").pw_gid
 
1052
1541
            except KeyError: