/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: 2015-03-10 18:03:38 UTC
  • mto: (237.7.304 trunk)
  • mto: This revision was merged to the branch mainline in revision 325.
  • Revision ID: teddy@recompile.se-20150310180338-pcxw6r2qmw9k6br9
Add ":!RSA" to GnuTLS priority string, to disallow non-DHE kx.

If Mandos was somehow made to use a non-ephemeral Diffie-Hellman key
exchange algorithm in the TLS handshake, any saved network traffic
could then be decrypted later if the Mandos client key was obtained.
By default, Mandos uses ephemeral DH key exchanges which does not have
this problem, but a non-ephemeral key exchange algorithm was still
enabled by default.  The simplest solution is to simply turn that off,
which ensures that Mandos will always use ephemeral DH key exchanges.

There is a "PFS" priority string specifier, but we can't use it because:

1. Security-wise, it is a mix between "NORMAL" and "SECURE128" - it
   enables a lot more algorithms than "SECURE256".

2. It is only available since GnuTLS 3.2.4.

Thanks to Andreas Fischer <af@bantuX.org> for reporting this issue.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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.6"
 
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):
179
175
    
180
176
    def checker_completed(self, exitstatus, condition, 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
184
        if os.WIFEXITED(condition):
189
 
            self.logger('Checker for client {0} (command "{1}")'
190
 
                        ' failed with exit code {2}'
 
185
            self.logger('Checker for client {} (command "{}") failed'
 
186
                        ' with exit code {}'
191
187
                        .format(self.properties["Name"], command,
192
188
                                os.WEXITSTATUS(condition)))
193
189
        elif os.WIFSIGNALED(condition):
194
 
            self.logger('Checker for client {0} (command "{1}") was'
195
 
                        ' killed by signal {2}'
 
190
            self.logger('Checker for client {} (command "{}") was'
 
191
                        ' killed by signal {}'
196
192
                        .format(self.properties["Name"], command,
197
193
                                os.WTERMSIG(condition)))
198
194
        elif os.WCOREDUMP(condition):
199
 
            self.logger('Checker for client {0} (command "{1}")'
200
 
                        ' dumped core'
201
 
                        .format(self.properties["Name"], command))
 
195
            self.logger('Checker for client {} (command "{}") dumped'
 
196
                        ' core'.format(self.properties["Name"],
 
197
                                       command))
202
198
        else:
203
 
            self.logger('Checker for client {0} completed'
 
199
            self.logger('Checker for client {} completed'
204
200
                        ' mysteriously'
205
201
                        .format(self.properties["Name"]))
206
202
        self.update()
207
203
    
208
204
    def checker_started(self, command):
209
205
        """Server signals that a checker started."""
210
 
        self.logger('Client {0} started checker "{1}"'
 
206
        self.logger('Client {} started checker "{}"'
211
207
                    .format(self.properties["Name"],
212
208
                            command), level=0)
213
209
    
214
210
    def got_secret(self):
215
 
        self.logger('Client {0} received its secret'
 
211
        self.logger('Client {} received its secret'
216
212
                    .format(self.properties["Name"]))
217
213
    
218
214
    def need_approval(self, timeout, default):
219
215
        if not default:
220
 
            message = 'Client {0} needs approval within {1} seconds'
 
216
            message = 'Client {} needs approval within {} seconds'
221
217
        else:
222
 
            message = 'Client {0} will get its secret in {1} seconds'
 
218
            message = 'Client {} will get its secret in {} seconds'
223
219
        self.logger(message.format(self.properties["Name"],
224
220
                                   timeout/1000))
225
221
    
226
222
    def rejected(self, reason):
227
 
        self.logger('Client {0} was rejected; reason: {1}'
 
223
        self.logger('Client {} was rejected; reason: {}'
228
224
                    .format(self.properties["Name"], reason))
229
225
    
230
226
    def selectable(self):
274
270
            else:
275
271
                timer = datetime.timedelta()
276
272
            if self.properties["ApprovedByDefault"]:
277
 
                message = "Approval in {0}. (d)eny?"
 
273
                message = "Approval in {}. (d)eny?"
278
274
            else:
279
 
                message = "Denial in {0}. (a)pprove?"
 
275
                message = "Denial in {}. (a)pprove?"
280
276
            message = message.format(str(timer).rsplit(".", 1)[0])
281
277
            self.using_timer(True)
282
278
        elif self.properties["LastCheckerStatus"] != 0:
290
286
                timer = max(expires - datetime.datetime.utcnow(),
291
287
                            datetime.timedelta())
292
288
            message = ('A checker has failed! Time until client'
293
 
                       ' gets disabled: {0}'
 
289
                       ' gets disabled: {}'
294
290
                       .format(str(timer).rsplit(".", 1)[0]))
295
291
            self.using_timer(True)
296
292
        else:
297
293
            message = "enabled"
298
294
            self.using_timer(False)
299
 
        self._text = "{0}{1}".format(base, message)
 
295
        self._text = "{}{}".format(base, message)
300
296
        
301
297
        if not urwid.supports_unicode():
302
298
            self._text = self._text.encode("ascii", "replace")
377
373
        else:
378
374
            return key
379
375
    
380
 
    def property_changed(self, property=None, **kwargs):
381
 
        """Call self.update() if old value is not new value.
 
376
    def properties_changed(self, interface, properties, invalidated):
 
377
        """Call self.update() if any properties changed.
382
378
        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:
 
379
        old_values = { key: self.properties.get(key)
 
380
                       for key in properties.keys() }
 
381
        super(MandosClientWidget, self).properties_changed(
 
382
            interface, properties, invalidated)
 
383
        if any(old_values[key] != self.properties.get(key)
 
384
               for key in old_values):
388
385
            self.update()
389
386
 
390
387
 
469
466
        self.main_loop = gobject.MainLoop()
470
467
    
471
468
    def client_not_found(self, fingerprint, address):
472
 
        self.log_message("Client with address {0} and fingerprint"
473
 
                         " {1} could not be found"
 
469
        self.log_message("Client with address {} and fingerprint {}"
 
470
                         " could not be found"
474
471
                         .format(address, fingerprint))
475
472
    
476
473
    def rebuild(self):
494
491
        if level < self.log_level:
495
492
            return
496
493
        timestamp = datetime.datetime.now().isoformat()
497
 
        self.log_message_raw("{0}: {1}".format(timestamp, message),
 
494
        self.log_message_raw("{}: {}".format(timestamp, message),
498
495
                             level=level)
499
496
    
500
497
    def log_message_raw(self, markup, level=1):
513
510
        """Toggle visibility of the log buffer."""
514
511
        self.log_visible = not self.log_visible
515
512
        self.rebuild()
516
 
        self.log_message("Log visibility changed to: {0}"
 
513
        self.log_message("Log visibility changed to: {}"
517
514
                         .format(self.log_visible), level=0)
518
515
    
519
516
    def change_log_display(self):
525
522
            self.log_wrap = "clip"
526
523
        for textwidget in self.log:
527
524
            textwidget.set_wrap_mode(self.log_wrap)
528
 
        self.log_message("Wrap mode: {0}".format(self.log_wrap),
 
525
        self.log_message("Wrap mode: {}".format(self.log_wrap),
529
526
                         level=0)
530
527
    
531
528
    def find_and_remove_client(self, path, name):
537
534
            client = self.clients_dict[path]
538
535
        except KeyError:
539
536
            # not found?
540
 
            self.log_message("Unknown client {0!r} ({1!r}) removed"
 
537
            self.log_message("Unknown client {!r} ({!r}) removed"
541
538
                             .format(name, path))
542
539
            return
543
540
        client.delete()
661
658
            elif key == "window resize":
662
659
                self.size = self.screen.get_cols_rows()
663
660
                self.refresh()
664
 
            elif key == "\f":  # Ctrl-L
 
661
            elif key == "ctrl l":
 
662
                self.screen.clear()
665
663
                self.refresh()
666
664
            elif key == "l" or key == "D":
667
665
                self.toggle_log_display()