/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

  • Committer: Teddy Hogeborn
  • Date: 2016-03-17 20:40:55 UTC
  • Revision ID: teddy@recompile.se-20160317204055-bhsh5xsidq7w5cxu
Client: Fix plymouth agent; broken since 1.7.2.

Fix an very old memory bug in the plymouth agent (which has been
present since its apperance in version 1.2), but which was only
recently detected at run time due to the new -fsanitize=address
compile- time flag, which has been used since version 1.7.2.  This
detection of a memory access violation causes the program to abort,
making the Plymouth graphical boot system unable to accept interactive
input of passwords when using the Mandos client.

* plugins.d/plymouth.c (exec_and_wait): Fix memory allocation bug when
  allocating new_argv.  Also tolerate a zero-length argv.

Show diffs side-by-side

added added

removed removed

Lines of Context:
79
79
 
80
80
import dbus
81
81
import dbus.service
82
 
try:
83
 
    from gi.repository import GObject
84
 
except ImportError:
85
 
    import gobject as GObject
 
82
from gi.repository import GLib
86
83
from dbus.mainloop.glib import DBusGMainLoop
87
84
import ctypes
88
85
import ctypes.util
100
97
if sys.version_info.major == 2:
101
98
    str = unicode
102
99
 
103
 
version = "1.7.5"
 
100
version = "1.7.6"
104
101
stored_state_file = "clients.pickle"
105
102
 
106
103
logger = logging.getLogger()
757
754
    checker:    subprocess.Popen(); a running checker process used
758
755
                                    to see if the client lives.
759
756
                                    'None' if no process is running.
760
 
    checker_callback_tag: a GObject event source tag, or None
 
757
    checker_callback_tag: a GLib event source tag, or None
761
758
    checker_command: string; External command which is run to check
762
759
                     if client lives.  %() expansions are done at
763
760
                     runtime with vars(self) as dict, so that for
764
761
                     instance %(name)s can be used in the command.
765
 
    checker_initiator_tag: a GObject event source tag, or None
 
762
    checker_initiator_tag: a GLib event source tag, or None
766
763
    created:    datetime.datetime(); (UTC) object creation
767
764
    client_structure: Object describing what attributes a client has
768
765
                      and is used for storing the client at exit
769
766
    current_checker_command: string; current running checker_command
770
 
    disable_initiator_tag: a GObject event source tag, or None
 
767
    disable_initiator_tag: a GLib event source tag, or None
771
768
    enabled:    bool()
772
769
    fingerprint: string (40 or 32 hexadecimal digits); used to
773
770
                 uniquely identify the client
929
926
        if not quiet:
930
927
            logger.info("Disabling client %s", self.name)
931
928
        if getattr(self, "disable_initiator_tag", None) is not None:
932
 
            GObject.source_remove(self.disable_initiator_tag)
 
929
            GLib.source_remove(self.disable_initiator_tag)
933
930
            self.disable_initiator_tag = None
934
931
        self.expires = None
935
932
        if getattr(self, "checker_initiator_tag", None) is not None:
936
 
            GObject.source_remove(self.checker_initiator_tag)
 
933
            GLib.source_remove(self.checker_initiator_tag)
937
934
            self.checker_initiator_tag = None
938
935
        self.stop_checker()
939
936
        self.enabled = False
940
937
        if not quiet:
941
938
            self.send_changedstate()
942
 
        # Do not run this again if called by a GObject.timeout_add
 
939
        # Do not run this again if called by a GLib.timeout_add
943
940
        return False
944
941
    
945
942
    def __del__(self):
949
946
        # Schedule a new checker to be started an 'interval' from now,
950
947
        # and every interval from then on.
951
948
        if self.checker_initiator_tag is not None:
952
 
            GObject.source_remove(self.checker_initiator_tag)
953
 
        self.checker_initiator_tag = GObject.timeout_add(
 
949
            GLib.source_remove(self.checker_initiator_tag)
 
950
        self.checker_initiator_tag = GLib.timeout_add(
954
951
            int(self.interval.total_seconds() * 1000),
955
952
            self.start_checker)
956
953
        # Schedule a disable() when 'timeout' has passed
957
954
        if self.disable_initiator_tag is not None:
958
 
            GObject.source_remove(self.disable_initiator_tag)
959
 
        self.disable_initiator_tag = GObject.timeout_add(
 
955
            GLib.source_remove(self.disable_initiator_tag)
 
956
        self.disable_initiator_tag = GLib.timeout_add(
960
957
            int(self.timeout.total_seconds() * 1000), self.disable)
961
958
        # Also start a new checker *right now*.
962
959
        self.start_checker()
998
995
        if timeout is None:
999
996
            timeout = self.timeout
1000
997
        if self.disable_initiator_tag is not None:
1001
 
            GObject.source_remove(self.disable_initiator_tag)
 
998
            GLib.source_remove(self.disable_initiator_tag)
1002
999
            self.disable_initiator_tag = None
1003
1000
        if getattr(self, "enabled", False):
1004
 
            self.disable_initiator_tag = GObject.timeout_add(
 
1001
            self.disable_initiator_tag = GLib.timeout_add(
1005
1002
                int(timeout.total_seconds() * 1000), self.disable)
1006
1003
            self.expires = datetime.datetime.utcnow() + timeout
1007
1004
    
1062
1059
                args = (pipe[1], subprocess.call, command),
1063
1060
                kwargs = popen_args)
1064
1061
            self.checker.start()
1065
 
            self.checker_callback_tag = GObject.io_add_watch(
1066
 
                pipe[0].fileno(), GObject.IO_IN,
 
1062
            self.checker_callback_tag = GLib.io_add_watch(
 
1063
                pipe[0].fileno(), GLib.IO_IN,
1067
1064
                self.checker_callback, pipe[0], command)
1068
 
        # Re-run this periodically if run by GObject.timeout_add
 
1065
        # Re-run this periodically if run by GLib.timeout_add
1069
1066
        return True
1070
1067
    
1071
1068
    def stop_checker(self):
1072
1069
        """Force the checker process, if any, to stop."""
1073
1070
        if self.checker_callback_tag:
1074
 
            GObject.source_remove(self.checker_callback_tag)
 
1071
            GLib.source_remove(self.checker_callback_tag)
1075
1072
            self.checker_callback_tag = None
1076
1073
        if getattr(self, "checker", None) is None:
1077
1074
            return
1832
1829
    
1833
1830
    def approve(self, value=True):
1834
1831
        self.approved = value
1835
 
        GObject.timeout_add(int(self.approval_duration.total_seconds()
1836
 
                                * 1000), self._reset_approved)
 
1832
        GLib.timeout_add(int(self.approval_duration.total_seconds()
 
1833
                             * 1000), self._reset_approved)
1837
1834
        self.send_changedstate()
1838
1835
    
1839
1836
    ## D-Bus methods, signals & properties
2049
2046
                if (getattr(self, "disable_initiator_tag", None)
2050
2047
                    is None):
2051
2048
                    return
2052
 
                GObject.source_remove(self.disable_initiator_tag)
2053
 
                self.disable_initiator_tag = GObject.timeout_add(
 
2049
                GLib.source_remove(self.disable_initiator_tag)
 
2050
                self.disable_initiator_tag = GLib.timeout_add(
2054
2051
                    int((self.expires - now).total_seconds() * 1000),
2055
2052
                    self.disable)
2056
2053
    
2076
2073
            return
2077
2074
        if self.enabled:
2078
2075
            # Reschedule checker run
2079
 
            GObject.source_remove(self.checker_initiator_tag)
2080
 
            self.checker_initiator_tag = GObject.timeout_add(
 
2076
            GLib.source_remove(self.checker_initiator_tag)
 
2077
            self.checker_initiator_tag = GLib.timeout_add(
2081
2078
                value, self.start_checker)
2082
2079
            self.start_checker() # Start one now, too
2083
2080
    
2487
2484
        gnutls_priority GnuTLS priority string
2488
2485
        use_dbus:       Boolean; to emit D-Bus signals or not
2489
2486
    
2490
 
    Assumes a GObject.MainLoop event loop.
 
2487
    Assumes a GLib.MainLoop event loop.
2491
2488
    """
2492
2489
    
2493
2490
    def __init__(self, server_address, RequestHandlerClass,
2518
2515
    
2519
2516
    def add_pipe(self, parent_pipe, proc):
2520
2517
        # Call "handle_ipc" for both data and EOF events
2521
 
        GObject.io_add_watch(
 
2518
        GLib.io_add_watch(
2522
2519
            parent_pipe.fileno(),
2523
 
            GObject.IO_IN | GObject.IO_HUP,
 
2520
            GLib.IO_IN | GLib.IO_HUP,
2524
2521
            functools.partial(self.handle_ipc,
2525
2522
                              parent_pipe = parent_pipe,
2526
2523
                              proc = proc))
2530
2527
                   proc = None,
2531
2528
                   client_object=None):
2532
2529
        # error, or the other end of multiprocessing.Pipe has closed
2533
 
        if condition & (GObject.IO_ERR | GObject.IO_HUP):
 
2530
        if condition & (GLib.IO_ERR | GLib.IO_HUP):
2534
2531
            # Wait for other process to exit
2535
2532
            proc.join()
2536
2533
            return False
2557
2554
                parent_pipe.send(False)
2558
2555
                return False
2559
2556
            
2560
 
            GObject.io_add_watch(
 
2557
            GLib.io_add_watch(
2561
2558
                parent_pipe.fileno(),
2562
 
                GObject.IO_IN | GObject.IO_HUP,
 
2559
                GLib.IO_IN | GLib.IO_HUP,
2563
2560
                functools.partial(self.handle_ipc,
2564
2561
                                  parent_pipe = parent_pipe,
2565
2562
                                  proc = proc,
2995
2992
        # Close all input and output, do double fork, etc.
2996
2993
        daemon()
2997
2994
    
2998
 
    # multiprocessing will use threads, so before we use GObject we
2999
 
    # need to inform GObject that threads will be used.
3000
 
    GObject.threads_init()
 
2995
    # multiprocessing will use threads, so before we use GLib we need
 
2996
    # to inform GLib that threads will be used.
 
2997
    GLib.threads_init()
3001
2998
    
3002
2999
    global main_loop
3003
3000
    # From the Avahi example code
3004
3001
    DBusGMainLoop(set_as_default=True)
3005
 
    main_loop = GObject.MainLoop()
 
3002
    main_loop = GLib.MainLoop()
3006
3003
    bus = dbus.SystemBus()
3007
3004
    # End of Avahi example code
3008
3005
    if use_dbus:
3066
3063
                                      else key): value
3067
3064
                                     for key, value in
3068
3065
                                     bytes_clients_data.items() }
 
3066
                    del bytes_clients_data
3069
3067
                    for key in clients_data:
3070
3068
                        value = { (k.decode("utf-8")
3071
3069
                                   if isinstance(k, bytes) else k): v
3083
3081
                            if isinstance(value[k], bytes):
3084
3082
                                value[k] = value[k].decode("utf-8")
3085
3083
                    ## old_client_settings
3086
 
                    # .keys
 
3084
                    # .keys()
3087
3085
                    old_client_settings = {
3088
3086
                        (key.decode("utf-8")
3089
3087
                         if isinstance(key, bytes)
3090
3088
                         else key): value
3091
3089
                        for key, value in
3092
3090
                        bytes_old_client_settings.items() }
 
3091
                    del bytes_old_client_settings
3093
3092
                    # .host
3094
3093
                    for value in old_client_settings.values():
3095
 
                        value["host"] = value["host"].decode("utf-8")
 
3094
                        if isinstance(value["host"], bytes):
 
3095
                            value["host"] = (value["host"]
 
3096
                                             .decode("utf-8"))
3096
3097
            os.remove(stored_state_path)
3097
3098
        except IOError as e:
3098
3099
            if e.errno == errno.ENOENT:
3199
3200
        del pidfile
3200
3201
        del pidfilename
3201
3202
    
3202
 
    signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
3203
 
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
 
3203
    for termsig in (signal.SIGHUP, signal.SIGTERM):
 
3204
        GLib.unix_signal_add(GLib.PRIORITY_HIGH, termsig,
 
3205
                             lambda: main_loop.quit() and False)
3204
3206
    
3205
3207
    if use_dbus:
3206
3208
        
3417
3419
                sys.exit(1)
3418
3420
            # End of Avahi example code
3419
3421
        
3420
 
        GObject.io_add_watch(tcp_server.fileno(), GObject.IO_IN,
3421
 
                             lambda *args, **kwargs:
3422
 
                             (tcp_server.handle_request
3423
 
                              (*args[2:], **kwargs) or True))
 
3422
        GLib.io_add_watch(tcp_server.fileno(), GLib.IO_IN,
 
3423
                          lambda *args, **kwargs:
 
3424
                          (tcp_server.handle_request
 
3425
                           (*args[2:], **kwargs) or True))
3424
3426
        
3425
3427
        logger.debug("Starting main loop")
3426
3428
        main_loop.run()