/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
42
42
 
43
43
import dbus
44
44
 
45
 
if sys.version_info[0] == 2:
 
45
if sys.version_info.major == 2:
46
46
    str = unicode
47
47
 
48
48
locale.setlocale(locale.LC_ALL, "")
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
 
def timedelta_to_milliseconds(td):
78
 
    """Convert a datetime.timedelta object to milliseconds"""
79
 
    return ((td.days * 24 * 60 * 60 * 1000)
80
 
            + (td.seconds * 1000)
81
 
            + (td.microseconds // 1000))
82
77
 
83
78
def milliseconds_to_string(ms):
84
79
    td = datetime.timedelta(0, 0, 0, ms)
85
 
    return ("{days}{hours:02}:{minutes:02}:{seconds:02}"
86
 
            .format(days = "{0}T".format(td.days) if td.days else "",
87
 
                    hours = td.seconds // 3600,
88
 
                    minutes = (td.seconds % 3600) // 60,
89
 
                    seconds = td.seconds % 60,
90
 
                    ))
 
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))
91
85
 
92
86
 
93
87
def rfc3339_duration_to_delta(duration):
117
111
    # avoid excessive use of external libraries.
118
112
    
119
113
    # New type for defining tokens, syntax, and semantics all-in-one
120
 
    Token = collections.namedtuple("Token",
121
 
                                   ("regexp", # To match token; if
122
 
                                              # "value" is not None,
123
 
                                              # must have a "group"
124
 
                                              # containing digits
125
 
                                    "value",  # datetime.timedelta or
126
 
                                              # None
127
 
                                    "followers")) # Tokens valid after
128
 
                                                  # 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
129
119
    # RFC 3339 "duration" tokens, syntax, and semantics; taken from
130
120
    # the "duration" ABNF definition in RFC 3339, Appendix A.
131
121
    token_end = Token(re.compile(r"$"), None, frozenset())
132
122
    token_second = Token(re.compile(r"(\d+)S"),
133
123
                         datetime.timedelta(seconds=1),
134
 
                         frozenset((token_end,)))
 
124
                         frozenset((token_end, )))
135
125
    token_minute = Token(re.compile(r"(\d+)M"),
136
126
                         datetime.timedelta(minutes=1),
137
127
                         frozenset((token_second, token_end)))
153
143
                       frozenset((token_month, token_end)))
154
144
    token_week = Token(re.compile(r"(\d+)W"),
155
145
                       datetime.timedelta(weeks=1),
156
 
                       frozenset((token_end,)))
 
146
                       frozenset((token_end, )))
157
147
    token_duration = Token(re.compile(r"P"), None,
158
148
                           frozenset((token_year, token_month,
159
149
                                      token_day, token_time,
161
151
    # Define starting values
162
152
    value = datetime.timedelta() # Value so far
163
153
    found_token = None
164
 
    followers = frozenset((token_duration,)) # Following valid tokens
 
154
    followers = frozenset((token_duration, )) # Following valid tokens
165
155
    s = duration                # String left to parse
166
156
    # Loop until end token is found
167
157
    while found_token is not token_end:
184
174
                break
185
175
        else:
186
176
            # No currently valid tokens were found
187
 
            raise ValueError("Invalid RFC 3339 duration")
 
177
            raise ValueError("Invalid RFC 3339 duration: {!r}"
 
178
                             .format(duration))
188
179
    # End token found
189
180
    return value
190
181
 
192
183
def string_to_delta(interval):
193
184
    """Parse a string and return a datetime.timedelta
194
185
    
195
 
    >>> string_to_delta("7d")
 
186
    >>> string_to_delta('7d')
196
187
    datetime.timedelta(7)
197
 
    >>> string_to_delta("60s")
 
188
    >>> string_to_delta('60s')
198
189
    datetime.timedelta(0, 60)
199
 
    >>> string_to_delta("60m")
 
190
    >>> string_to_delta('60m')
200
191
    datetime.timedelta(0, 3600)
201
 
    >>> string_to_delta("24h")
 
192
    >>> string_to_delta('24h')
202
193
    datetime.timedelta(1)
203
 
    >>> string_to_delta("1w")
 
194
    >>> string_to_delta('1w')
204
195
    datetime.timedelta(7)
205
 
    >>> string_to_delta("5m 30s")
 
196
    >>> string_to_delta('5m 30s')
206
197
    datetime.timedelta(0, 330)
207
198
    """
208
199
    
229
220
            value += datetime.timedelta(0, 0, 0, int(num))
230
221
    return value
231
222
 
 
223
 
232
224
def print_clients(clients, keywords):
233
225
    def valuetostring(value, keyword):
234
226
        if type(value) is dbus.Boolean:
240
232
    
241
233
    # Create format string to print table rows
242
234
    format_string = " ".join("{{{key}:{width}}}".format(
243
 
            width = max(len(tablewords[key]),
244
 
                        max(len(valuetostring(client[key],
245
 
                                              key))
246
 
                            for client in
247
 
                            clients)),
248
 
            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)
249
240
    # Print header line
250
241
    print(format_string.format(**tablewords))
251
242
    for client in clients:
252
 
        print(format_string.format(**{ key:
253
 
                                           valuetostring(client[key],
254
 
                                                         key)
255
 
                                       for key in keywords }))
 
243
        print(format_string.format(**{
 
244
            key: valuetostring(client[key], key)
 
245
            for key in keywords }))
 
246
 
256
247
 
257
248
def has_actions(options):
258
249
    return any((options.enable,
274
265
                options.approve,
275
266
                options.deny))
276
267
 
 
268
 
277
269
def main():
278
270
    parser = argparse.ArgumentParser()
279
271
    parser.add_argument("--version", action="version",
280
 
                        version = "%(prog)s {0}".format(version),
 
272
                        version = "%(prog)s {}".format(version),
281
273
                        help="show version number and exit")
282
274
    parser.add_argument("-a", "--all", action="store_true",
283
275
                        help="Select all clients")
344
336
        bus = dbus.SystemBus()
345
337
        mandos_dbus_objc = bus.get_object(busname, server_path)
346
338
    except dbus.exceptions.DBusException:
347
 
        print("Could not connect to Mandos server",
348
 
              file=sys.stderr)
 
339
        print("Could not connect to Mandos server", file=sys.stderr)
349
340
        sys.exit(1)
350
341
    
351
342
    mandos_serv = dbus.Interface(mandos_dbus_objc,
376
367
                    for path, properties in mandos_clients.items() }
377
368
    else:
378
369
        for name in options.client:
379
 
            for path, client in mandos_clients.iteritems():
 
370
            for path, client in mandos_clients.items():
380
371
                if client["Name"] == name:
381
372
                    client_objc = bus.get_object(busname, path)
382
373
                    clients[client_objc] = client
383
374
                    break
384
375
            else:
385
 
                print("Client not found on server: {0!r}"
 
376
                print("Client not found on server: {!r}"
386
377
                      .format(name), file=sys.stderr)
387
378
                sys.exit(1)
388
379
    
389
380
    if not has_actions(options) and clients:
390
381
        if options.verbose:
391
 
            keywords = ("Name", "Enabled", "Timeout",
392
 
                        "LastCheckedOK", "Created", "Interval",
393
 
                        "Host", "Fingerprint", "CheckerRunning",
394
 
                        "LastEnabled", "ApprovalPending",
395
 
                        "ApprovedByDefault",
 
382
            keywords = ("Name", "Enabled", "Timeout", "LastCheckedOK",
 
383
                        "Created", "Interval", "Host", "Fingerprint",
 
384
                        "CheckerRunning", "LastEnabled",
 
385
                        "ApprovalPending", "ApprovedByDefault",
396
386
                        "LastApprovalRequest", "ApprovalDelay",
397
387
                        "ApprovalDuration", "Checker",
398
388
                        "ExtendedTimeout")
403
393
    else:
404
394
        # Process each client in the list by all selected options
405
395
        for client in clients:
 
396
            
406
397
            def set_client_prop(prop, value):
407
398
                """Set a Client D-Bus property"""
408
399
                client.Set(client_interface, prop, value,
409
400
                           dbus_interface=dbus.PROPERTIES_IFACE)
 
401
            
410
402
            def set_client_prop_ms(prop, value):
411
403
                """Set a Client D-Bus property, converted
412
404
                from a string to milliseconds."""
413
405
                set_client_prop(prop,
414
 
                                timedelta_to_milliseconds
415
 
                                (string_to_delta(value)))
 
406
                                string_to_delta(value).total_seconds()
 
407
                                * 1000)
 
408
            
416
409
            if options.remove:
417
410
                mandos_serv.RemoveClient(client.__dbus_object_path__)
418
411
            if options.enable:
462
455
                client.Approve(dbus.Boolean(False),
463
456
                               dbus_interface=client_interface)
464
457
 
 
458
 
465
459
if __name__ == "__main__":
466
460
    main()