/mandos/release

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

« back to all changes in this revision

Viewing changes to mandos-monitor

  • Committer: Teddy Hogeborn
  • Date: 2013-10-24 20:25:54 UTC
  • mfrom: (237.7.182 trunk)
  • Revision ID: teddy@recompile.se-20131024202554-nb00jm6khi280lum
Merge from trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
4
4
# Mandos Monitor - Control and monitor the Mandos server
5
5
6
 
# Copyright © 2009-2012 Teddy Hogeborn
7
 
# Copyright © 2009-2012 Björn Påhlsson
 
6
# Copyright © 2009-2013 Teddy Hogeborn
 
7
# Copyright © 2009-2013 Björn Påhlsson
8
8
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
25
25
 
26
26
from __future__ import (division, absolute_import, print_function,
27
27
                        unicode_literals)
28
 
 
29
 
from future_builtins import *
 
28
try:
 
29
    from future_builtins import *
 
30
except ImportError:
 
31
    pass
30
32
 
31
33
import sys
32
34
import os
38
40
import urwid
39
41
 
40
42
from dbus.mainloop.glib import DBusGMainLoop
41
 
import gobject
 
43
try:
 
44
    import gobject
 
45
except ImportError:
 
46
    from gi.repository import GObject as gobject
42
47
 
43
48
import dbus
44
49
 
45
 
import UserList
46
 
 
47
50
import locale
48
51
 
 
52
if sys.version_info[0] == 2:
 
53
    str = unicode
 
54
 
49
55
locale.setlocale(locale.LC_ALL, '')
50
56
 
51
57
import logging
55
61
domain = 'se.recompile'
56
62
server_interface = domain + '.Mandos'
57
63
client_interface = domain + '.Mandos.Client'
58
 
version = "1.5.3"
59
 
 
60
 
# Always run in monochrome mode
61
 
urwid.curses_display.curses.has_colors = lambda : False
62
 
 
63
 
# Urwid doesn't support blinking, but we want it.  Since we have no
64
 
# use for underline on its own, we make underline also always blink.
65
 
urwid.curses_display.curses.A_UNDERLINE |= (
66
 
    urwid.curses_display.curses.A_BLINK)
 
64
version = "1.6.1"
67
65
 
68
66
def isoformat_to_datetime(iso):
69
67
    "Parse an ISO 8601 date string to a datetime.datetime()"
134
132
        self.logger = logger
135
133
        
136
134
        self._update_timer_callback_tag = None
137
 
        self._update_timer_callback_lock = 0
138
135
        
139
136
        # The widget shown normally
140
137
        self._text_widget = urwid.Text("")
144
141
        self.update()
145
142
        self.opened = False
146
143
        
147
 
        last_checked_ok = isoformat_to_datetime(self.properties
148
 
                                                ["LastCheckedOK"])
149
 
        
150
 
        if self.properties ["LastCheckerStatus"] != 0:
151
 
            self.using_timer(True)
152
 
        
153
 
        if self.need_approval:
154
 
            self.using_timer(True)
155
 
        
156
144
        self.match_objects = (
157
145
            self.proxy.connect_to_signal("CheckerCompleted",
158
146
                                         self.checker_completed,
177
165
        #self.logger('Created client {0}'
178
166
        #            .format(self.properties["Name"]))
179
167
    
180
 
    def property_changed(self, property=None, value=None):
181
 
        super(self, MandosClientWidget).property_changed(property,
182
 
                                                         value)
183
 
        if property == "ApprovalPending":
184
 
            using_timer(bool(value))
185
 
        if property == "LastCheckerStatus":
186
 
            using_timer(value != 0)
187
 
            #self.logger('Checker for client {0} (command "{1}") was '
188
 
            #            ' successful'.format(self.properties["Name"],
189
 
            #                                 command))
190
 
    
191
168
    def using_timer(self, flag):
192
169
        """Call this method with True or False when timer should be
193
170
        activated or deactivated.
194
171
        """
195
 
        old = self._update_timer_callback_lock
196
 
        if flag:
197
 
            self._update_timer_callback_lock += 1
198
 
        else:
199
 
            self._update_timer_callback_lock -= 1
200
 
        if old == 0 and self._update_timer_callback_lock:
 
172
        if flag and self._update_timer_callback_tag is None:
201
173
            # Will update the shown timer value every second
202
174
            self._update_timer_callback_tag = (gobject.timeout_add
203
175
                                               (1000,
204
176
                                                self.update_timer))
205
 
        elif old and self._update_timer_callback_lock == 0:
 
177
        elif not (flag or self._update_timer_callback_tag is None):
206
178
            gobject.source_remove(self._update_timer_callback_tag)
207
179
            self._update_timer_callback_tag = None
208
180
    
236
208
           to log in the future. """
237
209
        #self.logger('Client {0} started checker "{1}"'
238
210
        #            .format(self.properties["Name"],
239
 
        #                    unicode(command)))
 
211
        #                    str(command)))
240
212
        pass
241
213
    
242
214
    def got_secret(self):
250
222
            message = 'Client {0} will get its secret in {1} seconds'
251
223
        self.logger(message.format(self.properties["Name"],
252
224
                                   timeout/1000))
253
 
        self.using_timer(True)
254
225
    
255
226
    def rejected(self, reason):
256
227
        self.logger('Client {0} was rejected; reason: {1}'
282
253
                          "bold-underline-blink":
283
254
                              "bold-underline-blink-standout",
284
255
                          }
285
 
 
 
256
        
286
257
        # Rebuild focus and non-focus widgets using current properties
287
 
 
 
258
        
288
259
        # Base part of a client. Name!
289
260
        base = '{name}: '.format(name=self.properties["Name"])
290
261
        if not self.properties["Enabled"]:
291
262
            message = "DISABLED"
 
263
            self.using_timer(False)
292
264
        elif self.properties["ApprovalPending"]:
293
265
            timeout = datetime.timedelta(milliseconds
294
266
                                         = self.properties
296
268
            last_approval_request = isoformat_to_datetime(
297
269
                self.properties["LastApprovalRequest"])
298
270
            if last_approval_request is not None:
299
 
                timer = timeout - (datetime.datetime.utcnow()
300
 
                                   - last_approval_request)
 
271
                timer = max(timeout - (datetime.datetime.utcnow()
 
272
                                       - last_approval_request),
 
273
                            datetime.timedelta())
301
274
            else:
302
275
                timer = datetime.timedelta()
303
276
            if self.properties["ApprovedByDefault"]:
304
277
                message = "Approval in {0}. (d)eny?"
305
278
            else:
306
279
                message = "Denial in {0}. (a)pprove?"
307
 
            message = message.format(unicode(timer).rsplit(".", 1)[0])
 
280
            message = message.format(str(timer).rsplit(".", 1)[0])
 
281
            self.using_timer(True)
308
282
        elif self.properties["LastCheckerStatus"] != 0:
309
283
            # When checker has failed, show timer until client expires
310
284
            expires = self.properties["Expires"]
313
287
            else:
314
288
                expires = (datetime.datetime.strptime
315
289
                           (expires, '%Y-%m-%dT%H:%M:%S.%f'))
316
 
                timer = expires - datetime.datetime.utcnow()
 
290
                timer = max(expires - datetime.datetime.utcnow(),
 
291
                            datetime.timedelta())
317
292
            message = ('A checker has failed! Time until client'
318
293
                       ' gets disabled: {0}'
319
 
                       .format(unicode(timer).rsplit(".", 1)[0]))
 
294
                       .format(str(timer).rsplit(".", 1)[0]))
 
295
            self.using_timer(True)
320
296
        else:
321
297
            message = "enabled"
 
298
            self.using_timer(False)
322
299
        self._text = "{0}{1}".format(base, message)
323
 
            
 
300
        
324
301
        if not urwid.supports_unicode():
325
302
            self._text = self._text.encode("ascii", "replace")
326
303
        textlist = [("normal", self._text)]
403
380
    def property_changed(self, property=None, **kwargs):
404
381
        """Call self.update() if old value is not new value.
405
382
        This overrides the method from MandosClientPropertyCache"""
406
 
        property_name = unicode(property)
 
383
        property_name = str(property)
407
384
        old_value = self.properties.get(property_name)
408
385
        super(MandosClientWidget, self).property_changed(
409
386
            property=property, **kwargs)
436
413
                ("normal",
437
414
                 "default", "default", None),
438
415
                ("bold",
439
 
                 "default", "default", "bold"),
 
416
                 "bold", "default", "bold"),
440
417
                ("underline-blink",
441
 
                 "default", "default", "underline"),
 
418
                 "underline,blink", "default", "underline,blink"),
442
419
                ("standout",
443
 
                 "default", "default", "standout"),
 
420
                 "standout", "default", "standout"),
444
421
                ("bold-underline-blink",
445
 
                 "default", "default", ("bold", "underline")),
 
422
                 "bold,underline,blink", "default", "bold,underline,blink"),
446
423
                ("bold-standout",
447
 
                 "default", "default", ("bold", "standout")),
 
424
                 "bold,standout", "default", "bold,standout"),
448
425
                ("underline-blink-standout",
449
 
                 "default", "default", ("underline", "standout")),
 
426
                 "underline,blink,standout", "default",
 
427
                 "underline,blink,standout"),
450
428
                ("bold-underline-blink-standout",
451
 
                 "default", "default", ("bold", "underline",
452
 
                                          "standout")),
 
429
                 "bold,underline,blink,standout", "default",
 
430
                 "bold,underline,blink,standout"),
453
431
                ))
454
432
        
455
433
        if urwid.supports_unicode():
510
488
        self.topwidget = urwid.Pile(self.uilist)
511
489
    
512
490
    def log_message(self, message):
 
491
        """Log message formatted with timestamp"""
513
492
        timestamp = datetime.datetime.now().isoformat()
514
493
        self.log_message_raw(timestamp + ": " + message)
515
494
    
528
507
        self.log_visible = not self.log_visible
529
508
        self.rebuild()
530
509
        #self.log_message("Log visibility changed to: "
531
 
        #                 + unicode(self.log_visible))
 
510
        #                 + str(self.log_visible))
532
511
    
533
512
    def change_log_display(self):
534
513
        """Change type of log display.
574
553
        if path is None:
575
554
            path = client.proxy.object_path
576
555
        self.clients_dict[path] = client
577
 
        self.clients.sort(None, lambda c: c.properties["Name"])
 
556
        self.clients.sort(key=lambda c: c.properties["Name"])
578
557
        self.refresh()
579
558
    
580
559
    def remove_client(self, client, path=None):
582
561
        if path is None:
583
562
            path = client.proxy.object_path
584
563
        del self.clients_dict[path]
585
 
        if not self.clients_dict:
586
 
            # Work around bug in Urwid 0.9.8.3 - if a SimpleListWalker
587
 
            # is completely emptied, we need to recreate it.
588
 
            self.clients = urwid.SimpleListWalker([])
589
 
            self.rebuild()
590
564
        self.refresh()
591
565
    
592
566
    def refresh(self):
605
579
        try:
606
580
            mandos_clients = (self.mandos_serv
607
581
                              .GetAllClientsWithProperties())
 
582
            if not mandos_clients:
 
583
                self.log_message_raw(("bold", "Note: Server has no clients."))
608
584
        except dbus.exceptions.DBusException:
 
585
            self.log_message_raw(("bold", "Note: No Mandos server running."))
609
586
            mandos_clients = dbus.Dictionary()
610
587
        
611
588
        (self.mandos_serv
623
600
                            self.client_not_found,
624
601
                            dbus_interface=server_interface,
625
602
                            byte_arrays=True))
626
 
        for path, client in mandos_clients.iteritems():
 
603
        for path, client in mandos_clients.items():
627
604
            client_proxy_object = self.bus.get_object(self.busname,
628
605
                                                      path)
629
606
            self.add_client(MandosClientWidget(server_proxy_object
741
718
    ui.run()
742
719
except KeyboardInterrupt:
743
720
    ui.screen.stop()
744
 
except Exception, e:
745
 
    ui.log_message(unicode(e))
 
721
except Exception as e:
 
722
    ui.log_message(str(e))
746
723
    ui.screen.stop()
747
724
    raise