4
4
# Mandos Monitor - Control and monitor the Mandos server
 
6
 
# Copyright © 2009-2012 Teddy Hogeborn
 
7
 
# Copyright © 2009-2012 Björn Påhlsson
 
 
6
# Copyright © 2009-2011 Teddy Hogeborn
 
 
7
# Copyright © 2009-2011 Björn Påhlsson
 
9
9
# This program is free software: you can redistribute it and/or modify
 
10
10
# it under the terms of the GNU General Public License as published by
 
 
19
19
# You should have received a copy of the GNU General Public License
 
20
20
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
22
 
# Contact the authors at <mandos@recompile.se>.
 
 
22
# Contact the authors at <mandos@fukt.bsnet.se>.
 
25
 
from __future__ import (division, absolute_import, print_function,
 
 
25
from __future__ import division, absolute_import, print_function, unicode_literals
 
 
49
48
logging.getLogger('dbus.proxies').setLevel(logging.CRITICAL)
 
51
50
# Some useful constants
 
52
 
domain = 'se.recompile'
 
 
51
domain = 'se.bsnet.fukt'
 
53
52
server_interface = domain + '.Mandos'
 
54
53
client_interface = domain + '.Mandos.Client'
 
57
56
# Always run in monochrome mode
 
58
57
urwid.curses_display.curses.has_colors = lambda : False
 
 
87
86
        self.proxy = proxy_object # Mandos Client proxy object
 
89
88
        self.properties = dict()
 
90
 
        self.property_changed_match = (
 
91
 
            self.proxy.connect_to_signal("PropertyChanged",
 
92
 
                                         self.property_changed,
 
 
89
        self.proxy.connect_to_signal("PropertyChanged",
 
 
90
                                     self.property_changed,
 
96
94
        self.properties.update(
 
97
95
            self.proxy.GetAll(client_interface,
 
98
96
                              dbus_interface = dbus.PROPERTIES_IFACE))
 
100
 
        #XXX This breaks good super behaviour
 
 
98
        #XXX This break good super behaviour!
 
101
99
#        super(MandosClientPropertyCache, self).__init__(
 
102
100
#            *args, **kwargs)
 
 
108
106
        # Update properties dict with new value
 
109
107
        self.properties[property] = value
 
111
 
    def delete(self, *args, **kwargs):
 
112
 
        self.property_changed_match.remove()
 
113
 
        super(MandosClientPropertyCache, self).__init__(
 
117
110
class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
 
 
161
154
        if self.need_approval:
 
162
155
            self.using_timer(True)
 
164
 
        self.match_objects = (
 
165
 
            self.proxy.connect_to_signal("CheckerCompleted",
 
166
 
                                         self.checker_completed,
 
169
 
            self.proxy.connect_to_signal("CheckerStarted",
 
170
 
                                         self.checker_started,
 
173
 
            self.proxy.connect_to_signal("GotSecret",
 
177
 
            self.proxy.connect_to_signal("NeedApproval",
 
181
 
            self.proxy.connect_to_signal("Rejected",
 
185
 
        #self.logger('Created client %s' % (self.properties["Name"]))
 
 
157
        self.proxy.connect_to_signal("CheckerCompleted",
 
 
158
                                     self.checker_completed,
 
 
161
        self.proxy.connect_to_signal("CheckerStarted",
 
 
162
                                     self.checker_started,
 
 
165
        self.proxy.connect_to_signal("GotSecret",
 
 
169
        self.proxy.connect_to_signal("NeedApproval",
 
 
173
        self.proxy.connect_to_signal("Rejected",
 
187
178
    def property_changed(self, property=None, value=None):
 
188
179
        super(self, MandosClientWidget).property_changed(property,
 
 
244
234
    def checker_started(self, command):
 
245
 
        """Server signals that a checker started. This could be useful
 
246
 
           to log in the future. """
 
247
235
        #self.logger('Client %s started checker "%s"'
 
248
236
        #            % (self.properties["Name"], unicode(command)))
 
 
317
305
                message = "Denial in %s. (a)pprove?"
 
318
306
            message = message % unicode(timer).rsplit(".", 1)[0]
 
319
307
        elif self.last_checker_failed:
 
320
 
            # When checker has failed, print a timer until client expires
 
321
 
            expires = self.properties["Expires"]
 
323
 
                timer = datetime.timedelta(0)
 
325
 
                expires = datetime.datetime.strptime(expires,
 
326
 
                                                     '%Y-%m-%dT%H:%M:%S.%f')
 
327
 
                timer = expires - datetime.datetime.utcnow()
 
 
308
            timeout = datetime.timedelta(milliseconds
 
 
311
            last_ok = isoformat_to_datetime(
 
 
312
                max((self.properties["LastCheckedOK"]
 
 
313
                     or self.properties["Created"]),
 
 
314
                    self.properties["LastEnabled"]))
 
 
315
            timer = timeout - (datetime.datetime.utcnow() - last_ok)
 
328
316
            message = ('A checker has failed! Time until client'
 
329
317
                       ' gets disabled: %s'
 
330
318
                           % unicode(timer).rsplit(".", 1)[0])
 
 
349
337
            self.update_hook()
 
351
339
    def update_timer(self):
 
352
 
        """called by gobject. Will indefinitely loop until
 
353
 
        gobject.source_remove() on tag is called"""
 
355
342
        return True             # Keep calling this
 
357
 
    def delete(self, *args, **kwargs):
 
358
345
        if self._update_timer_callback_tag is not None:
 
359
346
            gobject.source_remove(self._update_timer_callback_tag)
 
360
347
            self._update_timer_callback_tag = None
 
361
 
        for match in self.match_objects:
 
363
 
        self.match_objects = ()
 
364
348
        if self.delete_hook is not None:
 
365
349
            self.delete_hook(self)
 
366
 
        return super(MandosClientWidget, self).delete(*args, **kwargs)
 
368
351
    def render(self, maxcolrow, focus=False):
 
369
352
        """Render differently if we have focus.
 
 
500
483
        self.busname = domain + '.Mandos'
 
501
484
        self.main_loop = gobject.MainLoop()
 
 
485
        self.bus = dbus.SystemBus()
 
 
486
        mandos_dbus_objc = self.bus.get_object(
 
 
487
            self.busname, "/", follow_name_owner_changes=True)
 
 
488
        self.mandos_serv = dbus.Interface(mandos_dbus_objc,
 
 
492
            mandos_clients = (self.mandos_serv
 
 
493
                              .GetAllClientsWithProperties())
 
 
494
        except dbus.exceptions.DBusException:
 
 
495
            mandos_clients = dbus.Dictionary()
 
 
498
         .connect_to_signal("ClientRemoved",
 
 
499
                            self.find_and_remove_client,
 
 
500
                            dbus_interface=server_interface,
 
 
503
         .connect_to_signal("ClientAdded",
 
 
505
                            dbus_interface=server_interface,
 
 
508
         .connect_to_signal("ClientNotFound",
 
 
509
                            self.client_not_found,
 
 
510
                            dbus_interface=server_interface,
 
 
512
        for path, client in mandos_clients.iteritems():
 
 
513
            client_proxy_object = self.bus.get_object(self.busname,
 
 
515
            self.add_client(MandosClientWidget(server_proxy_object
 
 
518
                                               =client_proxy_object,
 
503
528
    def client_not_found(self, fingerprint, address):
 
504
529
        self.log_message(("Client with address %s and fingerprint %s"
 
 
554
580
        #self.log_message("Wrap mode: " + self.log_wrap)
 
556
582
    def find_and_remove_client(self, path, name):
 
557
 
        """Find a client by its object path and remove it.
 
 
583
        """Find an client from its object path and remove it.
 
559
585
        This is connected to the ClientRemoved signal from the
 
560
586
        Mandos server object."""
 
 
562
588
            client = self.clients_dict[path]
 
565
 
            self.log_message("Unknown client %r (%r) removed", name,
 
 
592
        self.remove_client(client, path)
 
570
594
    def add_new_client(self, path):
 
571
595
        client_proxy_object = self.bus.get_object(self.busname, path)
 
 
610
634
        """Start the main loop and exit when it's done."""
 
611
 
        self.bus = dbus.SystemBus()
 
612
 
        mandos_dbus_objc = self.bus.get_object(
 
613
 
            self.busname, "/", follow_name_owner_changes=True)
 
614
 
        self.mandos_serv = dbus.Interface(mandos_dbus_objc,
 
618
 
            mandos_clients = (self.mandos_serv
 
619
 
                              .GetAllClientsWithProperties())
 
620
 
        except dbus.exceptions.DBusException:
 
621
 
            mandos_clients = dbus.Dictionary()
 
624
 
         .connect_to_signal("ClientRemoved",
 
625
 
                            self.find_and_remove_client,
 
626
 
                            dbus_interface=server_interface,
 
629
 
         .connect_to_signal("ClientAdded",
 
631
 
                            dbus_interface=server_interface,
 
634
 
         .connect_to_signal("ClientNotFound",
 
635
 
                            self.client_not_found,
 
636
 
                            dbus_interface=server_interface,
 
638
 
        for path, client in mandos_clients.iteritems():
 
639
 
            client_proxy_object = self.bus.get_object(self.busname,
 
641
 
            self.add_client(MandosClientWidget(server_proxy_object
 
644
 
                                               =client_proxy_object,
 
655
636
        self._input_callback_tag = (gobject.io_add_watch
 
656
637
                                    (sys.stdin.fileno(),