/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

* mandos: Change comment.
* mandos-clients.conf.xml (OPTIONS/checker): Rewrote without "you".
  (SEE ALSO): Reference fping(8).

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
from __future__ import (division, absolute_import, print_function,
27
27
                        unicode_literals)
28
28
 
 
29
from future_builtins import *
 
30
 
29
31
import sys
30
32
import os
31
33
import signal
53
55
domain = 'se.recompile'
54
56
server_interface = domain + '.Mandos'
55
57
client_interface = domain + '.Mandos.Client'
56
 
version = "1.5.3"
 
58
version = "1.5.4"
57
59
 
58
60
# Always run in monochrome mode
59
61
urwid.curses_display.curses.has_colors = lambda : False
84
86
    properties and calls a hook function when any of them are
85
87
    changed.
86
88
    """
87
 
    def __init__(self, proxy_object=None, *args, **kwargs):
 
89
    def __init__(self, proxy_object=None, properties=None, **kwargs):
88
90
        self.proxy = proxy_object # Mandos Client proxy object
89
 
        
90
 
        self.properties = dict()
 
91
        self.properties = dict() if properties is None else properties
91
92
        self.property_changed_match = (
92
93
            self.proxy.connect_to_signal("PropertyChanged",
93
 
                                         self.property_changed,
 
94
                                         self._property_changed,
94
95
                                         client_interface,
95
96
                                         byte_arrays=True))
96
97
        
97
 
        self.properties.update(
98
 
            self.proxy.GetAll(client_interface,
99
 
                              dbus_interface = dbus.PROPERTIES_IFACE))
100
 
 
101
 
        #XXX This breaks good super behaviour
102
 
#        super(MandosClientPropertyCache, self).__init__(
103
 
#            *args, **kwargs)
 
98
        if properties is None:
 
99
            self.properties.update(
 
100
                self.proxy.GetAll(client_interface,
 
101
                                  dbus_interface
 
102
                                  = dbus.PROPERTIES_IFACE))
 
103
        
 
104
        super(MandosClientPropertyCache, self).__init__(**kwargs)
 
105
    
 
106
    def _property_changed(self, property, value):
 
107
        """Helper which takes positional arguments"""
 
108
        return self.property_changed(property=property, value=value)
104
109
    
105
110
    def property_changed(self, property=None, value=None):
106
111
        """This is called whenever we get a PropertyChanged signal
109
114
        # Update properties dict with new value
110
115
        self.properties[property] = value
111
116
    
112
 
    def delete(self, *args, **kwargs):
 
117
    def delete(self):
113
118
        self.property_changed_match.remove()
114
 
        super(MandosClientPropertyCache, self).__init__(
115
 
            *args, **kwargs)
116
119
 
117
120
 
118
121
class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
120
123
    """
121
124
    
122
125
    def __init__(self, server_proxy_object=None, update_hook=None,
123
 
                 delete_hook=None, logger=None, *args, **kwargs):
 
126
                 delete_hook=None, logger=None, **kwargs):
124
127
        # Called on update
125
128
        self.update_hook = update_hook
126
129
        # Called on delete
131
134
        self.logger = logger
132
135
        
133
136
        self._update_timer_callback_tag = None
134
 
        self._update_timer_callback_lock = 0
135
137
        
136
138
        # The widget shown normally
137
139
        self._text_widget = urwid.Text("")
138
140
        # The widget shown when we have focus
139
141
        self._focus_text_widget = urwid.Text("")
140
 
        super(MandosClientWidget, self).__init__(
141
 
            update_hook=update_hook, delete_hook=delete_hook,
142
 
            *args, **kwargs)
 
142
        super(MandosClientWidget, self).__init__(**kwargs)
143
143
        self.update()
144
144
        self.opened = False
145
145
        
146
 
        last_checked_ok = isoformat_to_datetime(self.properties
147
 
                                                ["LastCheckedOK"])
148
 
        
149
 
        if self.properties ["LastCheckerStatus"] != 0:
150
 
            self.using_timer(True)
151
 
        
152
 
        if self.need_approval:
153
 
            self.using_timer(True)
154
 
        
155
146
        self.match_objects = (
156
147
            self.proxy.connect_to_signal("CheckerCompleted",
157
148
                                         self.checker_completed,
176
167
        #self.logger('Created client {0}'
177
168
        #            .format(self.properties["Name"]))
178
169
    
179
 
    def property_changed(self, property=None, value=None):
180
 
        super(self, MandosClientWidget).property_changed(property,
181
 
                                                         value)
182
 
        if property == "ApprovalPending":
183
 
            using_timer(bool(value))
184
 
        if property == "LastCheckerStatus":
185
 
            using_timer(value != 0)
186
 
            #self.logger('Checker for client {0} (command "{1}") was '
187
 
            #            ' successful'.format(self.properties["Name"],
188
 
            #                                 command))
189
 
    
190
170
    def using_timer(self, flag):
191
171
        """Call this method with True or False when timer should be
192
172
        activated or deactivated.
193
173
        """
194
 
        old = self._update_timer_callback_lock
195
 
        if flag:
196
 
            self._update_timer_callback_lock += 1
197
 
        else:
198
 
            self._update_timer_callback_lock -= 1
199
 
        if old == 0 and self._update_timer_callback_lock:
 
174
        if flag and self._update_timer_callback_tag is None:
200
175
            # Will update the shown timer value every second
201
176
            self._update_timer_callback_tag = (gobject.timeout_add
202
177
                                               (1000,
203
178
                                                self.update_timer))
204
 
        elif old and self._update_timer_callback_lock == 0:
 
179
        elif not (flag or self._update_timer_callback_tag is None):
205
180
            gobject.source_remove(self._update_timer_callback_tag)
206
181
            self._update_timer_callback_tag = None
207
182
    
249
224
            message = 'Client {0} will get its secret in {1} seconds'
250
225
        self.logger(message.format(self.properties["Name"],
251
226
                                   timeout/1000))
252
 
        self.using_timer(True)
253
227
    
254
228
    def rejected(self, reason):
255
229
        self.logger('Client {0} was rejected; reason: {1}'
281
255
                          "bold-underline-blink":
282
256
                              "bold-underline-blink-standout",
283
257
                          }
284
 
 
 
258
        
285
259
        # Rebuild focus and non-focus widgets using current properties
286
 
 
 
260
        
287
261
        # Base part of a client. Name!
288
262
        base = '{name}: '.format(name=self.properties["Name"])
289
263
        if not self.properties["Enabled"]:
290
264
            message = "DISABLED"
 
265
            self.using_timer(False)
291
266
        elif self.properties["ApprovalPending"]:
292
267
            timeout = datetime.timedelta(milliseconds
293
268
                                         = self.properties
295
270
            last_approval_request = isoformat_to_datetime(
296
271
                self.properties["LastApprovalRequest"])
297
272
            if last_approval_request is not None:
298
 
                timer = timeout - (datetime.datetime.utcnow()
299
 
                                   - last_approval_request)
 
273
                timer = max(timeout - (datetime.datetime.utcnow()
 
274
                                       - last_approval_request),
 
275
                            datetime.timedelta())
300
276
            else:
301
277
                timer = datetime.timedelta()
302
278
            if self.properties["ApprovedByDefault"]:
304
280
            else:
305
281
                message = "Denial in {0}. (a)pprove?"
306
282
            message = message.format(unicode(timer).rsplit(".", 1)[0])
 
283
            self.using_timer(True)
307
284
        elif self.properties["LastCheckerStatus"] != 0:
308
285
            # When checker has failed, show timer until client expires
309
286
            expires = self.properties["Expires"]
312
289
            else:
313
290
                expires = (datetime.datetime.strptime
314
291
                           (expires, '%Y-%m-%dT%H:%M:%S.%f'))
315
 
                timer = expires - datetime.datetime.utcnow()
 
292
                timer = max(expires - datetime.datetime.utcnow(),
 
293
                            datetime.timedelta())
316
294
            message = ('A checker has failed! Time until client'
317
295
                       ' gets disabled: {0}'
318
296
                       .format(unicode(timer).rsplit(".", 1)[0]))
 
297
            self.using_timer(True)
319
298
        else:
320
299
            message = "enabled"
 
300
            self.using_timer(False)
321
301
        self._text = "{0}{1}".format(base, message)
322
 
            
 
302
        
323
303
        if not urwid.supports_unicode():
324
304
            self._text = self._text.encode("ascii", "replace")
325
305
        textlist = [("normal", self._text)]
342
322
        self.update()
343
323
        return True             # Keep calling this
344
324
    
345
 
    def delete(self, *args, **kwargs):
 
325
    def delete(self, **kwargs):
346
326
        if self._update_timer_callback_tag is not None:
347
327
            gobject.source_remove(self._update_timer_callback_tag)
348
328
            self._update_timer_callback_tag = None
351
331
        self.match_objects = ()
352
332
        if self.delete_hook is not None:
353
333
            self.delete_hook(self)
354
 
        return super(MandosClientWidget, self).delete(*args, **kwargs)
 
334
        return super(MandosClientWidget, self).delete(**kwargs)
355
335
    
356
336
    def render(self, maxcolrow, focus=False):
357
337
        """Render differently if we have focus.
399
379
        else:
400
380
            return key
401
381
    
402
 
    def property_changed(self, property=None, value=None,
403
 
                         *args, **kwargs):
 
382
    def property_changed(self, property=None, **kwargs):
404
383
        """Call self.update() if old value is not new value.
405
384
        This overrides the method from MandosClientPropertyCache"""
406
385
        property_name = unicode(property)
407
386
        old_value = self.properties.get(property_name)
408
387
        super(MandosClientWidget, self).property_changed(
409
 
            property=property, value=value, *args, **kwargs)
 
388
            property=property, **kwargs)
410
389
        if self.properties.get(property_name) != old_value:
411
390
            self.update()
412
391
 
416
395
    "down" key presses, thus not allowing any containing widgets to
417
396
    use them as an excuse to shift focus away from this widget.
418
397
    """
419
 
    def keypress(self, maxcolrow, key):
420
 
        ret = super(ConstrainedListBox, self).keypress(maxcolrow, key)
 
398
    def keypress(self, *args, **kwargs):
 
399
        ret = super(ConstrainedListBox, self).keypress(*args, **kwargs)
421
400
        if ret in ("up", "down"):
422
401
            return
423
402
        return ret
638
617
                                               logger
639
618
                                               =self.log_message),
640
619
                            path=path)
641
 
 
 
620
        
642
621
        self.refresh()
643
622
        self._input_callback_tag = (gobject.io_add_watch
644
623
                                    (sys.stdin.fileno(),