/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: 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:
78
78
import tempfile
79
79
import itertools
80
80
import collections
 
81
import codecs
81
82
 
82
83
import dbus
83
84
import dbus.service
394
395
                    logger.error(bad_states[state] + ": %r", error)
395
396
            self.cleanup()
396
397
        elif state == avahi.SERVER_RUNNING:
397
 
            self.add()
 
398
            try:
 
399
                self.add()
 
400
            except dbus.exceptions.DBusException as error:
 
401
                if (error.get_dbus_name()
 
402
                    == "org.freedesktop.Avahi.CollisionError"):
 
403
                    logger.info("Local Zeroconf service name"
 
404
                                " collision.")
 
405
                    return self.rename(remove=False)
 
406
                else:
 
407
                    logger.critical("D-Bus Exception", exc_info=error)
 
408
                    self.cleanup()
 
409
                    os._exit(1)
398
410
        else:
399
411
            if error is None:
400
412
                logger.debug("Unknown state: %r", state)
423
435
            .format(self.name)))
424
436
        return ret
425
437
 
426
 
def subprocess_call_pipe(connection, # : multiprocessing.Connection
427
 
                         *args, **kwargs):
 
438
def call_pipe(connection,       # : multiprocessing.Connection
 
439
              func, *args, **kwargs):
428
440
    """This function is meant to be called by multiprocessing.Process
429
441
    
430
 
    This function runs a synchronous subprocess.call(), and writes the
431
 
    resulting return code on the provided multiprocessing.Connection.
 
442
    This function runs func(*args, **kwargs), and writes the resulting
 
443
    return value on the provided multiprocessing.Connection.
432
444
    """
433
 
    connection.send(subprocess.call(*args, **kwargs))
 
445
    connection.send(func(*args, **kwargs))
434
446
    connection.close()
435
447
 
436
448
class Client(object):
645
657
        # Also start a new checker *right now*.
646
658
        self.start_checker()
647
659
    
648
 
    def checker_callback(self, source, condition,
649
 
                         (connection, command)):
 
660
    def checker_callback(self, source, condition, connection,
 
661
                         command):
650
662
        """The checker has completed, so take appropriate actions."""
651
663
        self.checker_callback_tag = None
652
664
        self.checker = None
653
 
        # Read return code from connection (see subprocess_call_pipe)
 
665
        # Read return code from connection (see call_pipe)
654
666
        returncode = connection.recv()
655
667
        connection.close()
656
668
        
740
752
                and self.server_settings["foreground"]):
741
753
                popen_args.update({"stdout": wnull,
742
754
                                   "stderr": wnull })
743
 
            pipe = multiprocessing.Pipe(duplex=False)
 
755
            pipe = multiprocessing.Pipe(duplex = False)
744
756
            self.checker = multiprocessing.Process(
745
 
                target=subprocess_call_pipe, args=(pipe[1], command),
746
 
                kwargs=popen_args)
 
757
                target = call_pipe,
 
758
                args = (pipe[1], subprocess.call, command),
 
759
                kwargs = popen_args)
747
760
            self.checker.start()
748
761
            self.checker_callback_tag = gobject.io_add_watch(
749
762
                pipe[0].fileno(), gobject.IO_IN,
750
 
                self.checker_callback, (pipe[0], command))
 
763
                self.checker_callback, pipe[0], command)
751
764
        # Re-run this periodically if run by gobject.timeout_add
752
765
        return True
753
766
    
1097
1110
                interface_names.add(alt_interface)
1098
1111
                # Is this a D-Bus signal?
1099
1112
                if getattr(attribute, "_dbus_is_signal", False):
1100
 
                    # Extract the original non-method undecorated
1101
 
                    # function by black magic
1102
 
                    nonmethod_func = (dict(
1103
 
                        zip(attribute.func_code.co_freevars,
1104
 
                            attribute.__closure__))
1105
 
                                      ["func"].cell_contents)
 
1113
                    if sys.version_info.major == 2:
 
1114
                        # Extract the original non-method undecorated
 
1115
                        # function by black magic
 
1116
                        nonmethod_func = (dict(
 
1117
                            zip(attribute.func_code.co_freevars,
 
1118
                                attribute.__closure__))
 
1119
                                          ["func"].cell_contents)
 
1120
                    else:
 
1121
                        nonmethod_func = attribute
1106
1122
                    # Create a new, but exactly alike, function
1107
1123
                    # object, and decorate it to be a new D-Bus signal
1108
1124
                    # with the alternate D-Bus interface name
 
1125
                    if sys.version_info.major == 2:
 
1126
                        new_function = types.FunctionType(
 
1127
                            nonmethod_func.func_code,
 
1128
                            nonmethod_func.func_globals,
 
1129
                            nonmethod_func.func_name,
 
1130
                            nonmethod_func.func_defaults,
 
1131
                            nonmethod_func.func_closure)
 
1132
                    else:
 
1133
                        new_function = types.FunctionType(
 
1134
                            nonmethod_func.__code__,
 
1135
                            nonmethod_func.__globals__,
 
1136
                            nonmethod_func.__name__,
 
1137
                            nonmethod_func.__defaults__,
 
1138
                            nonmethod_func.__closure__)
1109
1139
                    new_function = (dbus.service.signal(
1110
 
                        alt_interface, attribute._dbus_signature)
1111
 
                                    (types.FunctionType(
1112
 
                                        nonmethod_func.func_code,
1113
 
                                        nonmethod_func.func_globals,
1114
 
                                        nonmethod_func.func_name,
1115
 
                                        nonmethod_func.func_defaults,
1116
 
                                        nonmethod_func.func_closure)))
 
1140
                        alt_interface,
 
1141
                        attribute._dbus_signature)(new_function))
1117
1142
                    # Copy annotations, if any
1118
1143
                    try:
1119
1144
                        new_function._dbus_annotations = dict(
1343
1368
        Client.__del__(self, *args, **kwargs)
1344
1369
    
1345
1370
    def checker_callback(self, source, condition,
1346
 
                         (connection, command), *args, **kwargs):
 
1371
                         connection, command, *args, **kwargs):
1347
1372
        ret = Client.checker_callback(self, source, condition,
1348
 
                                      (connection, command), *args,
 
1373
                                      connection, command, *args,
1349
1374
                                      **kwargs)
1350
1375
        exitstatus = self.last_checker_status
1351
1376
        if exitstatus >= 0:
1658
1683
        self._pipe = child_pipe
1659
1684
        self._pipe.send(('init', fpr, address))
1660
1685
        if not self._pipe.recv():
1661
 
            raise KeyError()
 
1686
            raise KeyError(fpr)
1662
1687
    
1663
1688
    def __getattribute__(self, name):
1664
1689
        if name == '_pipe':
2127
2152
        
2128
2153
        if command == 'getattr':
2129
2154
            attrname = request[1]
2130
 
            if callable(client_object.__getattribute__(attrname)):
 
2155
            if isinstance(client_object.__getattribute__(attrname),
 
2156
                          collections.Callable):
2131
2157
                parent_pipe.send(('function', ))
2132
2158
            else:
2133
2159
                parent_pipe.send((
2168
2194
    # avoid excessive use of external libraries.
2169
2195
    
2170
2196
    # New type for defining tokens, syntax, and semantics all-in-one
2171
 
    Token = collections.namedtuple("Token",
2172
 
                                   ("regexp", # To match token; if
2173
 
                                              # "value" is not None,
2174
 
                                              # must have a "group"
2175
 
                                              # containing digits
2176
 
                                    "value",  # datetime.timedelta or
2177
 
                                              # None
2178
 
                                    "followers")) # Tokens valid after
2179
 
                                                  # this token
2180
2197
    Token = collections.namedtuple("Token", (
2181
2198
        "regexp",  # To match token; if "value" is not None, must have
2182
2199
                   # a "group" containing digits
2217
2234
    # Define starting values
2218
2235
    value = datetime.timedelta() # Value so far
2219
2236
    found_token = None
2220
 
    followers = frozenset((token_duration,)) # Following valid tokens
 
2237
    followers = frozenset((token_duration, )) # Following valid tokens
2221
2238
    s = duration                # String left to parse
2222
2239
    # Loop until end token is found
2223
2240
    while found_token is not token_end:
2240
2257
                break
2241
2258
        else:
2242
2259
            # No currently valid tokens were found
2243
 
            raise ValueError("Invalid RFC 3339 duration")
 
2260
            raise ValueError("Invalid RFC 3339 duration: {!r}"
 
2261
                             .format(duration))
2244
2262
    # End token found
2245
2263
    return value
2246
2264
 
2379
2397
                        "debug": "False",
2380
2398
                        "priority":
2381
2399
                        "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:!RSA"
2382
 
                        ":+SIGN-RSA-SHA224:+SIGN-RSA-RMD160",
 
2400
                        ":+SIGN-DSA-SHA256",
2383
2401
                        "servicename": "Mandos",
2384
2402
                        "use_dbus": "True",
2385
2403
                        "use_ipv6": "True",
2497
2515
            pidfilename = "/var/run/mandos.pid"
2498
2516
        pidfile = None
2499
2517
        try:
2500
 
            pidfile = open(pidfilename, "w")
 
2518
            pidfile = codecs.open(pidfilename, "w", encoding="utf-8")
2501
2519
        except IOError as e:
2502
2520
            logger.error("Could not open file %r", pidfilename,
2503
2521
                         exc_info=e)
2562
2580
            old_bus_name = dbus.service.BusName(
2563
2581
                "se.bsnet.fukt.Mandos", bus,
2564
2582
                do_not_queue=True)
2565
 
        except dbus.exceptions.NameExistsException as e:
 
2583
        except dbus.exceptions.DBusException as e:
2566
2584
            logger.error("Disabling D-Bus:", exc_info=e)
2567
2585
            use_dbus = False
2568
2586
            server_settings["use_dbus"] = False
2699
2717
    
2700
2718
    if not foreground:
2701
2719
        if pidfile is not None:
 
2720
            pid = os.getpid()
2702
2721
            try:
2703
2722
                with pidfile:
2704
 
                    pid = os.getpid()
2705
 
                    pidfile.write("{}\n".format(pid).encode("utf-8"))
 
2723
                    print(pid, file=pidfile)
2706
2724
            except IOError:
2707
2725
                logger.error("Could not write to file %r with PID %d",
2708
2726
                             pidfilename, pid)