/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-monitor

  • Committer: Teddy Hogeborn
  • Date: 2014-06-07 20:27:17 UTC
  • Revision ID: teddy@recompile.se-20140607202717-j5hiiinwg6osy9ss
Minor bug fix in mandos-client: Allow periods in network hook names.

* plugins.d/mandos-client.c (runnable_hook): Add "." to strspn() call
                                             to match documentation.

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