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

  • Committer: teddy at recompile
  • Date: 2020-04-05 21:30:59 UTC
  • Revision ID: teddy@recompile.se-20200405213059-fb2a61ckqynrmatk
Fix file descriptor leak in mandos-client

When the local network has Mandos servers announcing themselves using
real, globally reachable, IPv6 addresses (i.e. not link-local
addresses), but there is no router on the local network providing IPv6
RA (Router Advertisement) packets, the client cannot reach the server
by normal means, since the client only has a link-local IPv6 address,
and has no usable route to reach the server's global IPv6 address.
(This is not a common situation, and usually only happens when the
router itself reboots and runs a Mandos client, since it cannot then
give RA packets to itself.)  The client code has a solution for
this, which consists of adding a temporary local route to reach the
address of the server during communication, and removing this
temporary route afterwards.

This solution with a temporary route works, but has a file descriptor
leak; it leaks one file descriptor for each addition and for each
removal of a route.  If one server requiring an added route is present
on the network, but no servers gives a password, making the client
retry after the default ten seconds, and we furthermore assume a
default 1024 open files limit, the client runs out of file descriptors
after about 90 minutes, after which time the client process will be
useless and fail to retrieve any passwords, necessitating manual
password entry via the keyboard.

Fix this by eliminating the file descriptor leak in the client.

* plugins.d/mandos-client.c (add_delete_local_route): Do
  close(devnull) also in parent process, also if fork() fails, and on
  any failure in child process.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python3 -bbI
2
2
# -*- after-save-hook: (lambda () (let ((command (if (fboundp 'file-local-name) (file-local-name (buffer-file-name)) (or (file-remote-p (buffer-file-name) 'localname) (buffer-file-name))))) (if (= (progn (if (get-buffer "*Test*") (kill-buffer "*Test*")) (process-file-shell-command (format "%s --check" (shell-quote-argument command)) nil "*Test*")) 0) (let ((w (get-buffer-window "*Test*"))) (if w (delete-window w))) (progn (with-current-buffer "*Test*" (compilation-mode)) (display-buffer "*Test*" '(display-buffer-in-side-window)))))); coding: utf-8 -*-
3
3
#
4
 
# Mandos Control - Control or query the Mandos server
 
4
# Mandos Monitor - Control and monitor the Mandos server
5
5
#
6
 
# Copyright © 2008-2020 Teddy Hogeborn
7
 
# Copyright © 2008-2020 Björn Påhlsson
 
6
# Copyright © 2008-2019 Teddy Hogeborn
 
7
# Copyright © 2008-2019 Björn Påhlsson
8
8
#
9
9
# This file is part of Mandos.
10
10
#
89
89
 
90
90
locale.setlocale(locale.LC_ALL, "")
91
91
 
92
 
version = "1.8.14"
 
92
version = "1.8.10"
93
93
 
94
94
 
95
95
def main():
726
726
            with self.convert_exception(dbus.Error):
727
727
                value =  method(*args)
728
728
            # DBussy returns values either as an empty list or as a
729
 
            # list of one element with the return value
 
729
            # tuple: (signature, value)
730
730
            if value:
731
731
                return self.type_filter(value[0])
732
732
 
738
738
 
739
739
        def type_filter(self, value):
740
740
            """Convert the most bothersome types to Python types"""
741
 
            # A D-Bus Variant value is represented as the Python type
742
 
            # Tuple[dbussy.DBUS.Signature, Any]
743
741
            if isinstance(value, tuple):
744
742
                if (len(value) == 2
745
743
                    and isinstance(value[0],
2439
2437
        busname = "se.recompile.Mandos"
2440
2438
        client_interface = "se.recompile.Mandos.Client"
2441
2439
        command.Approve().run(self.bus.clients, self.bus)
2442
 
        self.assertTrue(self.bus.clients)
2443
2440
        for clientpath in self.bus.clients:
2444
2441
            self.assertIn(("Approve", busname, clientpath,
2445
2442
                           client_interface, (True,)), self.bus.calls)
2448
2445
        busname = "se.recompile.Mandos"
2449
2446
        client_interface = "se.recompile.Mandos.Client"
2450
2447
        command.Deny().run(self.bus.clients, self.bus)
2451
 
        self.assertTrue(self.bus.clients)
2452
2448
        for clientpath in self.bus.clients:
2453
2449
            self.assertIn(("Approve", busname, clientpath,
2454
2450
                           client_interface, (False,)),
2455
2451
                          self.bus.calls)
2456
2452
 
2457
2453
    def test_Remove(self):
2458
 
        busname = "se.recompile.Mandos"
2459
 
        server_path = "/"
2460
 
        server_interface = "se.recompile.Mandos"
2461
 
        orig_clients = self.bus.clients.copy()
2462
2454
        command.Remove().run(self.bus.clients, self.bus)
2463
 
        self.assertFalse(self.bus.clients)
2464
 
        for clientpath in orig_clients:
2465
 
            self.assertIn(("RemoveClient", busname,
2466
 
                           server_path, server_interface,
 
2455
        for clientpath in self.bus.clients:
 
2456
            self.assertIn(("RemoveClient", dbus_busname,
 
2457
                           dbus_server_path, dbus_server_interface,
2467
2458
                           (clientpath,)), self.bus.calls)
2468
2459
 
2469
2460
    expected_json = {
2671
2662
        else:
2672
2663
            cmd_args = [() for x in range(len(self.values_to_get))]
2673
2664
            values_to_get = self.values_to_get
2674
 
        self.assertTrue(values_to_get)
2675
2665
        for value_to_get, cmd_arg in zip(values_to_get, cmd_args):
2676
2666
            for clientpath in self.bus.clients:
2677
2667
                self.bus.clients[clientpath][self.propname] = (
2678
2668
                    Unique())
2679
2669
            self.command(*cmd_arg).run(self.bus.clients, self.bus)
2680
 
            self.assertTrue(self.bus.clients)
2681
2670
            for clientpath in self.bus.clients:
2682
2671
                value = (self.bus.clients[clientpath]
2683
2672
                         [self.propname])