/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: 2015-07-20 03:03:33 UTC
  • Revision ID: teddy@recompile.se-20150720030333-203m2aeblypcsfte
Bug fix for GnuTLS 3: be compatible with old 2048-bit DSA keys.

The mandos-keygen program in Mandos version 1.6.0 and older generated
2048-bit DSA keys, and when GnuTLS uses these it has trouble
connecting using the Mandos default priority string.  This was
previously fixed in Mandos 1.6.2, but the bug reappeared when using
GnuTLS 3, so the default priority string has to change again; this
time also the Mandos client has to change its default, so now the
server and the client should use the same default priority string:

SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:!RSA:+SIGN-DSA-SHA256

* mandos (main/server_defaults): Changed default priority string.
* mandos-options.xml (/section/para[id="priority_compat"]): Removed.
  (/section/para[id="priority"]): Changed default priority string.
* mandos.conf ([DEFAULT]/priority): - '' -
* mandos.conf.xml (OPTIONS/priority): Refer to the id "priority"
                                      instead of "priority_compat".
* mandos.xml (OPTIONS/--priority): - '' -
* plugins.d/mandos-client.c (main): Changed default priority string.

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-2014 Teddy Hogeborn
7
 
# Copyright © 2009-2014 Björn Påhlsson
 
6
# Copyright © 2009-2015 Teddy Hogeborn
 
7
# Copyright © 2009-2015 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
48
48
 
49
49
import locale
50
50
 
51
 
if sys.version_info[0] == 2:
 
51
if sys.version_info.major == 2:
52
52
    str = unicode
53
53
 
54
54
locale.setlocale(locale.LC_ALL, '')
60
60
domain = 'se.recompile'
61
61
server_interface = domain + '.Mandos'
62
62
client_interface = domain + '.Mandos.Client'
63
 
version = "1.6.7"
 
63
version = "1.6.9"
64
64
 
65
65
def isoformat_to_datetime(iso):
66
66
    "Parse an ISO 8601 date string to a datetime.datetime()"
87
87
        self.proxy = proxy_object # Mandos Client proxy object
88
88
        self.properties = dict() if properties is None else properties
89
89
        self.property_changed_match = (
90
 
            self.proxy.connect_to_signal("PropertyChanged",
91
 
                                         self._property_changed,
92
 
                                         client_interface,
 
90
            self.proxy.connect_to_signal("PropertiesChanged",
 
91
                                         self.properties_changed,
 
92
                                         dbus.PROPERTIES_IFACE,
93
93
                                         byte_arrays=True))
94
94
        
95
95
        if properties is None:
100
100
        
101
101
        super(MandosClientPropertyCache, self).__init__(**kwargs)
102
102
    
103
 
    def _property_changed(self, property, value):
104
 
        """Helper which takes positional arguments"""
105
 
        return self.property_changed(property=property, value=value)
106
 
    
107
 
    def property_changed(self, property=None, value=None):
108
 
        """This is called whenever we get a PropertyChanged signal
109
 
        It updates the changed property in the "properties" dict.
 
103
    def properties_changed(self, interface, properties, invalidated):
 
104
        """This is called whenever we get a PropertiesChanged signal
 
105
        It updates the changed properties in the "properties" dict.
110
106
        """
111
107
        # Update properties dict with new value
112
 
        self.properties[property] = value
 
108
        self.properties.update(properties)
113
109
    
114
110
    def delete(self):
115
111
        self.property_changed_match.remove()
161
157
                                         self.rejected,
162
158
                                         client_interface,
163
159
                                         byte_arrays=True))
164
 
        self.logger('Created client {0}'
 
160
        self.logger('Created client {}'
165
161
                    .format(self.properties["Name"]), level=0)
166
162
    
167
163
    def using_timer(self, flag):
177
173
            gobject.source_remove(self._update_timer_callback_tag)
178
174
            self._update_timer_callback_tag = None
179
175
    
180
 
    def checker_completed(self, exitstatus, condition, command):
 
176
    def checker_completed(self, exitstatus, signal, command):
181
177
        if exitstatus == 0:
182
 
            self.logger('Checker for client {0} (command "{1}")'
 
178
            self.logger('Checker for client {} (command "{}")'
183
179
                        ' succeeded'.format(self.properties["Name"],
184
180
                                            command), level=0)
185
181
            self.update()
186
182
            return
187
183
        # Checker failed
188
 
        if os.WIFEXITED(condition):
189
 
            self.logger('Checker for client {0} (command "{1}")'
190
 
                        ' failed with exit code {2}'
191
 
                        .format(self.properties["Name"], command,
192
 
                                os.WEXITSTATUS(condition)))
193
 
        elif os.WIFSIGNALED(condition):
194
 
            self.logger('Checker for client {0} (command "{1}") was'
195
 
                        ' killed by signal {2}'
196
 
                        .format(self.properties["Name"], command,
197
 
                                os.WTERMSIG(condition)))
198
 
        elif os.WCOREDUMP(condition):
199
 
            self.logger('Checker for client {0} (command "{1}")'
200
 
                        ' dumped core'
201
 
                        .format(self.properties["Name"], command))
 
184
        if exitstatus >= 0:
 
185
            self.logger('Checker for client {} (command "{}") failed'
 
186
                        ' with exit code {}'
 
187
                        .format(self.properties["Name"], command,
 
188
                                exitstatus))
 
189
        elif signal != 0:
 
190
            self.logger('Checker for client {} (command "{}") was'
 
191
                        ' killed by signal {}'
 
192
                        .format(self.properties["Name"], command,
 
193
                                signal))
202
194
        else:
203
 
            self.logger('Checker for client {0} completed'
 
195
            self.logger('Checker for client {} completed'
204
196
                        ' mysteriously'
205
197
                        .format(self.properties["Name"]))
206
198
        self.update()
207
199
    
208
200
    def checker_started(self, command):
209
201
        """Server signals that a checker started."""
210
 
        self.logger('Client {0} started checker "{1}"'
 
202
        self.logger('Client {} started checker "{}"'
211
203
                    .format(self.properties["Name"],
212
204
                            command), level=0)
213
205
    
214
206
    def got_secret(self):
215
 
        self.logger('Client {0} received its secret'
 
207
        self.logger('Client {} received its secret'
216
208
                    .format(self.properties["Name"]))
217
209
    
218
210
    def need_approval(self, timeout, default):
219
211
        if not default:
220
 
            message = 'Client {0} needs approval within {1} seconds'
 
212
            message = 'Client {} needs approval within {} seconds'
221
213
        else:
222
 
            message = 'Client {0} will get its secret in {1} seconds'
 
214
            message = 'Client {} will get its secret in {} seconds'
223
215
        self.logger(message.format(self.properties["Name"],
224
216
                                   timeout/1000))
225
217
    
226
218
    def rejected(self, reason):
227
 
        self.logger('Client {0} was rejected; reason: {1}'
 
219
        self.logger('Client {} was rejected; reason: {}'
228
220
                    .format(self.properties["Name"], reason))
229
221
    
230
222
    def selectable(self):
274
266
            else:
275
267
                timer = datetime.timedelta()
276
268
            if self.properties["ApprovedByDefault"]:
277
 
                message = "Approval in {0}. (d)eny?"
 
269
                message = "Approval in {}. (d)eny?"
278
270
            else:
279
 
                message = "Denial in {0}. (a)pprove?"
 
271
                message = "Denial in {}. (a)pprove?"
280
272
            message = message.format(str(timer).rsplit(".", 1)[0])
281
273
            self.using_timer(True)
282
274
        elif self.properties["LastCheckerStatus"] != 0:
290
282
                timer = max(expires - datetime.datetime.utcnow(),
291
283
                            datetime.timedelta())
292
284
            message = ('A checker has failed! Time until client'
293
 
                       ' gets disabled: {0}'
 
285
                       ' gets disabled: {}'
294
286
                       .format(str(timer).rsplit(".", 1)[0]))
295
287
            self.using_timer(True)
296
288
        else:
297
289
            message = "enabled"
298
290
            self.using_timer(False)
299
 
        self._text = "{0}{1}".format(base, message)
 
291
        self._text = "{}{}".format(base, message)
300
292
        
301
293
        if not urwid.supports_unicode():
302
294
            self._text = self._text.encode("ascii", "replace")
377
369
        else:
378
370
            return key
379
371
    
380
 
    def property_changed(self, property=None, **kwargs):
381
 
        """Call self.update() if old value is not new value.
 
372
    def properties_changed(self, interface, properties, invalidated):
 
373
        """Call self.update() if any properties changed.
382
374
        This overrides the method from MandosClientPropertyCache"""
383
 
        property_name = str(property)
384
 
        old_value = self.properties.get(property_name)
385
 
        super(MandosClientWidget, self).property_changed(
386
 
            property=property, **kwargs)
387
 
        if self.properties.get(property_name) != old_value:
 
375
        old_values = { key: self.properties.get(key)
 
376
                       for key in properties.keys() }
 
377
        super(MandosClientWidget, self).properties_changed(
 
378
            interface, properties, invalidated)
 
379
        if any(old_values[key] != self.properties.get(key)
 
380
               for key in old_values):
388
381
            self.update()
389
382
 
390
383
 
469
462
        self.main_loop = gobject.MainLoop()
470
463
    
471
464
    def client_not_found(self, fingerprint, address):
472
 
        self.log_message("Client with address {0} and fingerprint"
473
 
                         " {1} could not be found"
 
465
        self.log_message("Client with address {} and fingerprint {}"
 
466
                         " could not be found"
474
467
                         .format(address, fingerprint))
475
468
    
476
469
    def rebuild(self):
494
487
        if level < self.log_level:
495
488
            return
496
489
        timestamp = datetime.datetime.now().isoformat()
497
 
        self.log_message_raw("{0}: {1}".format(timestamp, message),
 
490
        self.log_message_raw("{}: {}".format(timestamp, message),
498
491
                             level=level)
499
492
    
500
493
    def log_message_raw(self, markup, level=1):
513
506
        """Toggle visibility of the log buffer."""
514
507
        self.log_visible = not self.log_visible
515
508
        self.rebuild()
516
 
        self.log_message("Log visibility changed to: {0}"
 
509
        self.log_message("Log visibility changed to: {}"
517
510
                         .format(self.log_visible), level=0)
518
511
    
519
512
    def change_log_display(self):
525
518
            self.log_wrap = "clip"
526
519
        for textwidget in self.log:
527
520
            textwidget.set_wrap_mode(self.log_wrap)
528
 
        self.log_message("Wrap mode: {0}".format(self.log_wrap),
 
521
        self.log_message("Wrap mode: {}".format(self.log_wrap),
529
522
                         level=0)
530
523
    
531
524
    def find_and_remove_client(self, path, name):
537
530
            client = self.clients_dict[path]
538
531
        except KeyError:
539
532
            # not found?
540
 
            self.log_message("Unknown client {0!r} ({1!r}) removed"
 
533
            self.log_message("Unknown client {!r} ({!r}) removed"
541
534
                             .format(name, path))
542
535
            return
543
536
        client.delete()