/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: 2014-07-25 23:16:04 UTC
  • mto: This revision was merged to the branch mainline in revision 724.
  • Revision ID: teddy@recompile.se-20140725231604-f5c4f82rn2o5ll1k
Use the .items() method instead of .iteritems().

This is strictly not a Python 2.7 change, but Python 2.7 backported
the new .viewitems() from Python 3, and instead of changing .items()
to .viewitems() and later having to change them all into .items()
again in Python 3, I opted to just change all .iteritems() to .items()
so the code will work both now and with Python 3.  The slowdown with
Python 2 is not significant, and with Python 3 it will again be fast.

* mandos (Client.__init__): Use .items() instead of .iteritems().
  (DBusObjectWithProperties.Introspect): - '' -
  (alternate_dbus_interfaces/wrapper): - '' -
  (main): - '' -
* mandos-ctl (main): - '' -

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-2016 Teddy Hogeborn
7
 
# Copyright © 2008-2016 Björn Påhlsson
 
6
# Copyright © 2008-2014 Teddy Hogeborn
 
7
# Copyright © 2008-2014 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.major == 2:
 
45
if sys.version_info[0] == 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.7.7"
76
 
 
77
 
 
78
 
try:
79
 
    dbus.OBJECT_MANAGER_IFACE
80
 
except AttributeError:
81
 
    dbus.OBJECT_MANAGER_IFACE = "org.freedesktop.DBus.ObjectManager"
 
75
version = "1.6.7"
 
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
82
 
83
83
def milliseconds_to_string(ms):
84
84
    td = datetime.timedelta(0, 0, 0, ms)
85
 
    return ("{days}{hours:02}:{minutes:02}:{seconds:02}".format(
86
 
        days = "{}T".format(td.days) if td.days else "",
87
 
        hours = td.seconds // 3600,
88
 
        minutes = (td.seconds % 3600) // 60,
89
 
        seconds = td.seconds % 60))
 
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
                    ))
90
91
 
91
92
 
92
93
def rfc3339_duration_to_delta(duration):
116
117
    # avoid excessive use of external libraries.
117
118
    
118
119
    # New type for defining tokens, syntax, and semantics all-in-one
119
 
    Token = collections.namedtuple("Token", (
120
 
        "regexp",  # To match token; if "value" is not None, must have
121
 
                   # a "group" containing digits
122
 
        "value",   # datetime.timedelta or None
123
 
        "followers"))           # Tokens valid after this token
 
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
124
129
    # RFC 3339 "duration" tokens, syntax, and semantics; taken from
125
130
    # the "duration" ABNF definition in RFC 3339, Appendix A.
126
131
    token_end = Token(re.compile(r"$"), None, frozenset())
127
132
    token_second = Token(re.compile(r"(\d+)S"),
128
133
                         datetime.timedelta(seconds=1),
129
 
                         frozenset((token_end, )))
 
134
                         frozenset((token_end,)))
130
135
    token_minute = Token(re.compile(r"(\d+)M"),
131
136
                         datetime.timedelta(minutes=1),
132
137
                         frozenset((token_second, token_end)))
148
153
                       frozenset((token_month, token_end)))
149
154
    token_week = Token(re.compile(r"(\d+)W"),
150
155
                       datetime.timedelta(weeks=1),
151
 
                       frozenset((token_end, )))
 
156
                       frozenset((token_end,)))
152
157
    token_duration = Token(re.compile(r"P"), None,
153
158
                           frozenset((token_year, token_month,
154
159
                                      token_day, token_time,
156
161
    # Define starting values
157
162
    value = datetime.timedelta() # Value so far
158
163
    found_token = None
159
 
    followers = frozenset((token_duration, )) # Following valid tokens
 
164
    followers = frozenset((token_duration,)) # Following valid tokens
160
165
    s = duration                # String left to parse
161
166
    # Loop until end token is found
162
167
    while found_token is not token_end:
179
184
                break
180
185
        else:
181
186
            # No currently valid tokens were found
182
 
            raise ValueError("Invalid RFC 3339 duration: {!r}"
183
 
                             .format(duration))
 
187
            raise ValueError("Invalid RFC 3339 duration")
184
188
    # End token found
185
189
    return value
186
190
 
188
192
def string_to_delta(interval):
189
193
    """Parse a string and return a datetime.timedelta
190
194
    
191
 
    >>> string_to_delta('7d')
 
195
    >>> string_to_delta("7d")
192
196
    datetime.timedelta(7)
193
 
    >>> string_to_delta('60s')
 
197
    >>> string_to_delta("60s")
194
198
    datetime.timedelta(0, 60)
195
 
    >>> string_to_delta('60m')
 
199
    >>> string_to_delta("60m")
196
200
    datetime.timedelta(0, 3600)
197
 
    >>> string_to_delta('24h')
 
201
    >>> string_to_delta("24h")
198
202
    datetime.timedelta(1)
199
 
    >>> string_to_delta('1w')
 
203
    >>> string_to_delta("1w")
200
204
    datetime.timedelta(7)
201
 
    >>> string_to_delta('5m 30s')
 
205
    >>> string_to_delta("5m 30s")
202
206
    datetime.timedelta(0, 330)
203
207
    """
204
208
    
225
229
            value += datetime.timedelta(0, 0, 0, int(num))
226
230
    return value
227
231
 
228
 
 
229
232
def print_clients(clients, keywords):
230
233
    def valuetostring(value, keyword):
231
234
        if type(value) is dbus.Boolean:
237
240
    
238
241
    # Create format string to print table rows
239
242
    format_string = " ".join("{{{key}:{width}}}".format(
240
 
        width = max(len(tablewords[key]),
241
 
                    max(len(valuetostring(client[key], key))
242
 
                        for client in clients)),
243
 
        key = key)
244
 
                             for key in keywords)
 
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)
245
249
    # Print header line
246
250
    print(format_string.format(**tablewords))
247
251
    for client in clients:
248
 
        print(format_string.format(**{
249
 
            key: valuetostring(client[key], key)
250
 
            for key in keywords }))
251
 
 
 
252
        print(format_string.format(**{ key:
 
253
                                           valuetostring(client[key],
 
254
                                                         key)
 
255
                                       for key in keywords }))
252
256
 
253
257
def has_actions(options):
254
258
    return any((options.enable,
270
274
                options.approve,
271
275
                options.deny))
272
276
 
273
 
 
274
277
def main():
275
278
    parser = argparse.ArgumentParser()
276
279
    parser.add_argument("--version", action="version",
277
 
                        version = "%(prog)s {}".format(version),
 
280
                        version = "%(prog)s {0}".format(version),
278
281
                        help="show version number and exit")
279
282
    parser.add_argument("-a", "--all", action="store_true",
280
283
                        help="Select all clients")
341
344
        bus = dbus.SystemBus()
342
345
        mandos_dbus_objc = bus.get_object(busname, server_path)
343
346
    except dbus.exceptions.DBusException:
344
 
        print("Could not connect to Mandos server", file=sys.stderr)
 
347
        print("Could not connect to Mandos server",
 
348
              file=sys.stderr)
345
349
        sys.exit(1)
346
350
    
347
351
    mandos_serv = dbus.Interface(mandos_dbus_objc,
348
352
                                 dbus_interface = server_interface)
349
 
    mandos_serv_object_manager = dbus.Interface(
350
 
        mandos_dbus_objc, dbus_interface = dbus.OBJECT_MANAGER_IFACE)
351
353
    
352
354
    #block stderr since dbus library prints to stderr
353
355
    null = os.open(os.path.devnull, os.O_RDWR)
356
358
    os.close(null)
357
359
    try:
358
360
        try:
359
 
            mandos_clients = { path: ifs_and_props[client_interface]
360
 
                               for path, ifs_and_props in
361
 
                               mandos_serv_object_manager
362
 
                               .GetManagedObjects().items()
363
 
                               if client_interface in ifs_and_props }
 
361
            mandos_clients = mandos_serv.GetAllClientsWithProperties()
364
362
        finally:
365
363
            #restore stderr
366
364
            os.dup2(stderrcopy, sys.stderr.fileno())
367
365
            os.close(stderrcopy)
368
 
    except dbus.exceptions.DBusException as e:
369
 
        print("Access denied: Accessing mandos server through D-Bus: {}"
370
 
              .format(e), file=sys.stderr)
 
366
    except dbus.exceptions.DBusException:
 
367
        print("Access denied: Accessing mandos server through dbus.",
 
368
              file=sys.stderr)
371
369
        sys.exit(1)
372
370
    
373
371
    # Compile dict of (clients: properties) to process
384
382
                    clients[client_objc] = client
385
383
                    break
386
384
            else:
387
 
                print("Client not found on server: {!r}"
 
385
                print("Client not found on server: {0!r}"
388
386
                      .format(name), file=sys.stderr)
389
387
                sys.exit(1)
390
388
    
391
389
    if not has_actions(options) and clients:
392
390
        if options.verbose:
393
 
            keywords = ("Name", "Enabled", "Timeout", "LastCheckedOK",
394
 
                        "Created", "Interval", "Host", "Fingerprint",
395
 
                        "CheckerRunning", "LastEnabled",
396
 
                        "ApprovalPending", "ApprovedByDefault",
 
391
            keywords = ("Name", "Enabled", "Timeout",
 
392
                        "LastCheckedOK", "Created", "Interval",
 
393
                        "Host", "Fingerprint", "CheckerRunning",
 
394
                        "LastEnabled", "ApprovalPending",
 
395
                        "ApprovedByDefault",
397
396
                        "LastApprovalRequest", "ApprovalDelay",
398
397
                        "ApprovalDuration", "Checker",
399
398
                        "ExtendedTimeout")
404
403
    else:
405
404
        # Process each client in the list by all selected options
406
405
        for client in clients:
407
 
            
408
406
            def set_client_prop(prop, value):
409
407
                """Set a Client D-Bus property"""
410
408
                client.Set(client_interface, prop, value,
411
409
                           dbus_interface=dbus.PROPERTIES_IFACE)
412
 
            
413
410
            def set_client_prop_ms(prop, value):
414
411
                """Set a Client D-Bus property, converted
415
412
                from a string to milliseconds."""
416
413
                set_client_prop(prop,
417
 
                                string_to_delta(value).total_seconds()
418
 
                                * 1000)
419
 
            
 
414
                                timedelta_to_milliseconds
 
415
                                (string_to_delta(value)))
420
416
            if options.remove:
421
417
                mandos_serv.RemoveClient(client.__dbus_object_path__)
422
418
            if options.enable:
466
462
                client.Approve(dbus.Boolean(False),
467
463
                               dbus_interface=client_interface)
468
464
 
469
 
 
470
465
if __name__ == "__main__":
471
466
    main()