/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 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 © 2008-2014 Teddy Hogeborn
7
 
# Copyright © 2008-2014 Björn Påhlsson
 
6
# Copyright © 2008-2015 Teddy Hogeborn
 
7
# Copyright © 2008-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
64
64
    "ApprovalDelay": "Approval Delay",
65
65
    "ApprovalDuration": "Approval Duration",
66
66
    "Checker": "Checker",
67
 
    "ExtendedTimeout" : "Extended Timeout"
68
 
    }
 
67
    "ExtendedTimeout": "Extended Timeout"
 
68
}
69
69
defaultkeywords = ("Name", "Enabled", "Timeout", "LastCheckedOK")
70
70
domain = "se.recompile"
71
71
busname = domain + ".Mandos"
72
72
server_path = "/"
73
73
server_interface = domain + ".Mandos"
74
74
client_interface = domain + ".Mandos.Client"
75
 
version = "1.6.7"
 
75
version = "1.6.9"
 
76
 
76
77
 
77
78
def milliseconds_to_string(ms):
78
79
    td = datetime.timedelta(0, 0, 0, ms)
79
 
    return ("{days}{hours:02}:{minutes:02}:{seconds:02}"
80
 
            .format(days = "{}T".format(td.days) if td.days else "",
81
 
                    hours = td.seconds // 3600,
82
 
                    minutes = (td.seconds % 3600) // 60,
83
 
                    seconds = td.seconds % 60,
84
 
                    ))
 
80
    return ("{days}{hours:02}:{minutes:02}:{seconds:02}".format(
 
81
        days = "{}T".format(td.days) if td.days else "",
 
82
        hours = td.seconds // 3600,
 
83
        minutes = (td.seconds % 3600) // 60,
 
84
        seconds = td.seconds % 60))
85
85
 
86
86
 
87
87
def rfc3339_duration_to_delta(duration):
111
111
    # avoid excessive use of external libraries.
112
112
    
113
113
    # New type for defining tokens, syntax, and semantics all-in-one
114
 
    Token = collections.namedtuple("Token",
115
 
                                   ("regexp", # To match token; if
116
 
                                              # "value" is not None,
117
 
                                              # must have a "group"
118
 
                                              # containing digits
119
 
                                    "value",  # datetime.timedelta or
120
 
                                              # None
121
 
                                    "followers")) # Tokens valid after
122
 
                                                  # this token
 
114
    Token = collections.namedtuple("Token", (
 
115
        "regexp",  # To match token; if "value" is not None, must have
 
116
                   # a "group" containing digits
 
117
        "value",   # datetime.timedelta or None
 
118
        "followers"))           # Tokens valid after this token
123
119
    # RFC 3339 "duration" tokens, syntax, and semantics; taken from
124
120
    # the "duration" ABNF definition in RFC 3339, Appendix A.
125
121
    token_end = Token(re.compile(r"$"), None, frozenset())
126
122
    token_second = Token(re.compile(r"(\d+)S"),
127
123
                         datetime.timedelta(seconds=1),
128
 
                         frozenset((token_end,)))
 
124
                         frozenset((token_end, )))
129
125
    token_minute = Token(re.compile(r"(\d+)M"),
130
126
                         datetime.timedelta(minutes=1),
131
127
                         frozenset((token_second, token_end)))
147
143
                       frozenset((token_month, token_end)))
148
144
    token_week = Token(re.compile(r"(\d+)W"),
149
145
                       datetime.timedelta(weeks=1),
150
 
                       frozenset((token_end,)))
 
146
                       frozenset((token_end, )))
151
147
    token_duration = Token(re.compile(r"P"), None,
152
148
                           frozenset((token_year, token_month,
153
149
                                      token_day, token_time,
155
151
    # Define starting values
156
152
    value = datetime.timedelta() # Value so far
157
153
    found_token = None
158
 
    followers = frozenset((token_duration,)) # Following valid tokens
 
154
    followers = frozenset((token_duration, )) # Following valid tokens
159
155
    s = duration                # String left to parse
160
156
    # Loop until end token is found
161
157
    while found_token is not token_end:
178
174
                break
179
175
        else:
180
176
            # No currently valid tokens were found
181
 
            raise ValueError("Invalid RFC 3339 duration")
 
177
            raise ValueError("Invalid RFC 3339 duration: {!r}"
 
178
                             .format(duration))
182
179
    # End token found
183
180
    return value
184
181
 
186
183
def string_to_delta(interval):
187
184
    """Parse a string and return a datetime.timedelta
188
185
    
189
 
    >>> string_to_delta("7d")
 
186
    >>> string_to_delta('7d')
190
187
    datetime.timedelta(7)
191
 
    >>> string_to_delta("60s")
 
188
    >>> string_to_delta('60s')
192
189
    datetime.timedelta(0, 60)
193
 
    >>> string_to_delta("60m")
 
190
    >>> string_to_delta('60m')
194
191
    datetime.timedelta(0, 3600)
195
 
    >>> string_to_delta("24h")
 
192
    >>> string_to_delta('24h')
196
193
    datetime.timedelta(1)
197
 
    >>> string_to_delta("1w")
 
194
    >>> string_to_delta('1w')
198
195
    datetime.timedelta(7)
199
 
    >>> string_to_delta("5m 30s")
 
196
    >>> string_to_delta('5m 30s')
200
197
    datetime.timedelta(0, 330)
201
198
    """
202
199
    
223
220
            value += datetime.timedelta(0, 0, 0, int(num))
224
221
    return value
225
222
 
 
223
 
226
224
def print_clients(clients, keywords):
227
225
    def valuetostring(value, keyword):
228
226
        if type(value) is dbus.Boolean:
234
232
    
235
233
    # Create format string to print table rows
236
234
    format_string = " ".join("{{{key}:{width}}}".format(
237
 
            width = max(len(tablewords[key]),
238
 
                        max(len(valuetostring(client[key],
239
 
                                              key))
240
 
                            for client in
241
 
                            clients)),
242
 
            key = key) for key in keywords)
 
235
        width = max(len(tablewords[key]),
 
236
                    max(len(valuetostring(client[key], key))
 
237
                        for client in clients)),
 
238
        key = key)
 
239
                             for key in keywords)
243
240
    # Print header line
244
241
    print(format_string.format(**tablewords))
245
242
    for client in clients:
246
 
        print(format_string.format(**{ key:
247
 
                                           valuetostring(client[key],
248
 
                                                         key)
249
 
                                       for key in keywords }))
 
243
        print(format_string.format(**{
 
244
            key: valuetostring(client[key], key)
 
245
            for key in keywords }))
 
246
 
250
247
 
251
248
def has_actions(options):
252
249
    return any((options.enable,
268
265
                options.approve,
269
266
                options.deny))
270
267
 
 
268
 
271
269
def main():
272
270
    parser = argparse.ArgumentParser()
273
271
    parser.add_argument("--version", action="version",
338
336
        bus = dbus.SystemBus()
339
337
        mandos_dbus_objc = bus.get_object(busname, server_path)
340
338
    except dbus.exceptions.DBusException:
341
 
        print("Could not connect to Mandos server",
342
 
              file=sys.stderr)
 
339
        print("Could not connect to Mandos server", file=sys.stderr)
343
340
        sys.exit(1)
344
341
    
345
342
    mandos_serv = dbus.Interface(mandos_dbus_objc,
382
379
    
383
380
    if not has_actions(options) and clients:
384
381
        if options.verbose:
385
 
            keywords = ("Name", "Enabled", "Timeout",
386
 
                        "LastCheckedOK", "Created", "Interval",
387
 
                        "Host", "Fingerprint", "CheckerRunning",
388
 
                        "LastEnabled", "ApprovalPending",
389
 
                        "ApprovedByDefault",
 
382
            keywords = ("Name", "Enabled", "Timeout", "LastCheckedOK",
 
383
                        "Created", "Interval", "Host", "Fingerprint",
 
384
                        "CheckerRunning", "LastEnabled",
 
385
                        "ApprovalPending", "ApprovedByDefault",
390
386
                        "LastApprovalRequest", "ApprovalDelay",
391
387
                        "ApprovalDuration", "Checker",
392
388
                        "ExtendedTimeout")
397
393
    else:
398
394
        # Process each client in the list by all selected options
399
395
        for client in clients:
 
396
            
400
397
            def set_client_prop(prop, value):
401
398
                """Set a Client D-Bus property"""
402
399
                client.Set(client_interface, prop, value,
403
400
                           dbus_interface=dbus.PROPERTIES_IFACE)
 
401
            
404
402
            def set_client_prop_ms(prop, value):
405
403
                """Set a Client D-Bus property, converted
406
404
                from a string to milliseconds."""
407
405
                set_client_prop(prop,
408
406
                                string_to_delta(value).total_seconds()
409
407
                                * 1000)
 
408
            
410
409
            if options.remove:
411
410
                mandos_serv.RemoveClient(client.__dbus_object_path__)
412
411
            if options.enable:
456
455
                client.Approve(dbus.Boolean(False),
457
456
                               dbus_interface=client_interface)
458
457
 
 
458
 
459
459
if __name__ == "__main__":
460
460
    main()