/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to mandos-ctl

* mandos-ctl: Bug fix: only show properties of specifies clients.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
# -*- mode: python; coding: utf-8 -*-
 
3
 
 
4
from __future__ import division
 
5
import sys
 
6
import dbus
 
7
from optparse import OptionParser
 
8
import locale
 
9
import datetime
 
10
import re
 
11
import os
 
12
 
 
13
locale.setlocale(locale.LC_ALL, u'')
 
14
 
 
15
tablewords = {
 
16
    'Name': u'Name',
 
17
    'Enabled': u'Enabled',
 
18
    'Timeout': u'Timeout',
 
19
    'LastCheckedOK': u'Last Successful Check',
 
20
    'Created': u'Created',
 
21
    'Interval': u'Interval',
 
22
    'Host': u'Host',
 
23
    'Fingerprint': u'Fingerprint',
 
24
    'CheckerRunning': u'Check Is Running',
 
25
    'LastEnabled': u'Last Enabled',
 
26
    'Checker': u'Checker',
 
27
    }
 
28
defaultkeywords = ('Name', 'Enabled', 'Timeout', 'LastCheckedOK')
 
29
domain = 'se.bsnet.fukt'
 
30
busname = domain + '.Mandos'
 
31
server_path = '/'
 
32
server_interface = domain + '.Mandos'
 
33
client_interface = domain + '.Mandos.Client'
 
34
version = "1.0.14"
 
35
 
 
36
def timedelta_to_milliseconds(td):
 
37
    "Convert a datetime.timedelta object to milliseconds"
 
38
    return ((td.days * 24 * 60 * 60 * 1000)
 
39
            + (td.seconds * 1000)
 
40
            + (td.microseconds // 1000))
 
41
 
 
42
def milliseconds_to_string(ms):
 
43
    td = datetime.timedelta(0, 0, 0, ms)
 
44
    return (u"%(days)s%(hours)02d:%(minutes)02d:%(seconds)02d"
 
45
            % { "days": "%dT" % td.days if td.days else "",
 
46
                "hours": td.seconds // 3600,
 
47
                "minutes": (td.seconds % 3600) // 60,
 
48
                "seconds": td.seconds % 60,
 
49
                })
 
50
 
 
51
 
 
52
def string_to_delta(interval):
 
53
    """Parse a string and return a datetime.timedelta
 
54
 
 
55
    >>> string_to_delta('7d')
 
56
    datetime.timedelta(7)
 
57
    >>> string_to_delta('60s')
 
58
    datetime.timedelta(0, 60)
 
59
    >>> string_to_delta('60m')
 
60
    datetime.timedelta(0, 3600)
 
61
    >>> string_to_delta('24h')
 
62
    datetime.timedelta(1)
 
63
    >>> string_to_delta(u'1w')
 
64
    datetime.timedelta(7)
 
65
    >>> string_to_delta('5m 30s')
 
66
    datetime.timedelta(0, 330)
 
67
    """
 
68
    timevalue = datetime.timedelta(0)
 
69
    regexp = re.compile("\d+[dsmhw]")
 
70
    
 
71
    for s in regexp.findall(interval):
 
72
        try:
 
73
            suffix = unicode(s[-1])
 
74
            value = int(s[:-1])
 
75
            if suffix == u"d":
 
76
                delta = datetime.timedelta(value)
 
77
            elif suffix == u"s":
 
78
                delta = datetime.timedelta(0, value)
 
79
            elif suffix == u"m":
 
80
                delta = datetime.timedelta(0, 0, 0, 0, value)
 
81
            elif suffix == u"h":
 
82
                delta = datetime.timedelta(0, 0, 0, 0, 0, value)
 
83
            elif suffix == u"w":
 
84
                delta = datetime.timedelta(0, 0, 0, 0, 0, 0, value)
 
85
            else:
 
86
                raise ValueError
 
87
        except (ValueError, IndexError):
 
88
            raise ValueError
 
89
        timevalue += delta
 
90
    return timevalue
 
91
 
 
92
def print_clients(clients, keywords):
 
93
    def valuetostring(value, keyword):
 
94
        if type(value) is dbus.Boolean:
 
95
            return u"Yes" if value else u"No"
 
96
        if keyword in (u"timeout", u"interval"):
 
97
            return milliseconds_to_string(value)
 
98
        return unicode(value)
 
99
    
 
100
    # Create format string to print table rows
 
101
    format_string = u' '.join(u'%%-%ds' %
 
102
                              max(len(tablewords[key]),
 
103
                                  max(len(valuetostring(client[key],
 
104
                                                        key))
 
105
                                      for client in
 
106
                                      clients))
 
107
                              for key in keywords)
 
108
    # Print header line
 
109
    print format_string % tuple(tablewords[key] for key in keywords)
 
110
    for client in clients:
 
111
        print format_string % tuple(valuetostring(client[key], key)
 
112
                                    for key in keywords)
 
113
def has_actions(options):
 
114
    return any((options.enable,
 
115
                options.disable,
 
116
                options.bump_timeout,
 
117
                options.start_checker,
 
118
                options.stop_checker,
 
119
                options.is_enabled,
 
120
                options.remove,
 
121
                options.checker is not None,
 
122
                options.timeout is not None,
 
123
                options.interval is not None,
 
124
                options.host is not None,
 
125
                options.secret is not None,
 
126
                options.approve,
 
127
                options.deny))
 
128
        
 
129
def main():
 
130
        parser = OptionParser(version = "%%prog %s" % version)
 
131
        parser.add_option("-a", "--all", action="store_true",
 
132
                          help="Select all clients")
 
133
        parser.add_option("-v", "--verbose", action="store_true",
 
134
                          help="Print all fields")
 
135
        parser.add_option("-e", "--enable", action="store_true",
 
136
                          help="Enable client")
 
137
        parser.add_option("-d", "--disable", action="store_true",
 
138
                          help="disable client")
 
139
        parser.add_option("-b", "--bump-timeout", action="store_true",
 
140
                          help="Bump timeout for client")
 
141
        parser.add_option("--start-checker", action="store_true",
 
142
                          help="Start checker for client")
 
143
        parser.add_option("--stop-checker", action="store_true",
 
144
                          help="Stop checker for client")
 
145
        parser.add_option("-V", "--is-enabled", action="store_true",
 
146
                          help="Check if client is enabled")
 
147
        parser.add_option("-r", "--remove", action="store_true",
 
148
                          help="Remove client")
 
149
        parser.add_option("-c", "--checker", type="string",
 
150
                          help="Set checker command for client")
 
151
        parser.add_option("-t", "--timeout", type="string",
 
152
                          help="Set timeout for client")
 
153
        parser.add_option("-i", "--interval", type="string",
 
154
                          help="Set checker interval for client")
 
155
        parser.add_option("-H", "--host", type="string",
 
156
                          help="Set host for client")
 
157
        parser.add_option("-s", "--secret", type="string",
 
158
                          help="Set password blob (file) for client")
 
159
        parser.add_option("-A", "--approve", action="store_true",
 
160
                          help="Approve any current client request")
 
161
        parser.add_option("-D", "--deny", action="store_true",
 
162
                          help="Deny any current client request")
 
163
        options, client_names = parser.parse_args()
 
164
        
 
165
        if has_actions(options) and not client_names and not options.all:
 
166
            parser.error('Options requires clients names or --all.')
 
167
        if options.verbose and has_actions(options):
 
168
            parser.error('Verbose option can only be used alone or with --all.')
 
169
        if options.all and not has_actions(options):
 
170
            parser.error('--all requires an action')
 
171
            
 
172
        try:
 
173
            bus = dbus.SystemBus()
 
174
            mandos_dbus_objc = bus.get_object(busname, server_path)
 
175
        except dbus.exceptions.DBusException:
 
176
            print >> sys.stderr, "Could not connect to Mandos server"
 
177
            sys.exit(1)
 
178
    
 
179
        mandos_serv = dbus.Interface(mandos_dbus_objc,
 
180
                                     dbus_interface = server_interface)
 
181
 
 
182
        #block stderr since dbus library prints to stderr
 
183
        null = os.open(os.path.devnull, os.O_RDWR)
 
184
        stderrcopy = os.dup(sys.stderr.fileno())
 
185
        os.dup2(null, sys.stderr.fileno())
 
186
        os.close(null)
 
187
        try:
 
188
            try:
 
189
                mandos_clients = mandos_serv.GetAllClientsWithProperties()
 
190
            finally:
 
191
                #restore stderr
 
192
                os.dup2(stderrcopy, sys.stderr.fileno())
 
193
                os.close(stderrcopy)
 
194
        except dbus.exceptions.DBusException, e:
 
195
            print >> sys.stderr, "Access denied: Accessing mandos server through dbus."
 
196
            sys.exit(1)
 
197
            
 
198
        # Compile dict of (clients: properties) to process
 
199
        clients={}
 
200
        
 
201
        if options.all or not client_names:
 
202
            clients = dict((bus.get_object(busname, path), properties)
 
203
                           for path, properties in
 
204
                           mandos_clients.iteritems())
 
205
        else:
 
206
            for name in client_names:
 
207
                for path, client in mandos_clients.iteritems():
 
208
                    if client['Name'] == name:
 
209
                        client_objc = bus.get_object(busname, path)
 
210
                        clients[client_objc] = client
 
211
                        break
 
212
                else:
 
213
                    print >> sys.stderr, "Client not found on server: %r" % name
 
214
                    sys.exit(1)
 
215
            
 
216
        if not has_actions(options) and clients:
 
217
            if options.verbose:
 
218
                keywords = ('Name', 'Enabled', 'Timeout', 'LastCheckedOK',
 
219
                            'Created', 'Interval', 'Host', 'Fingerprint',
 
220
                            'CheckerRunning', 'LastEnabled', 'Checker')
 
221
            else:
 
222
                keywords = defaultkeywords
 
223
                
 
224
            print_clients(clients.values(), keywords)
 
225
        else:
 
226
            # Process each client in the list by all selected options
 
227
            for client in clients:
 
228
                if options.remove:
 
229
                    mandos_serv.RemoveClient(client.__dbus_object_path__)
 
230
                if options.enable:
 
231
                    client.Enable(dbus_interface=client_interface)
 
232
                if options.disable:
 
233
                    client.Disable(dbus_interface=client_interface)
 
234
                if options.bump_timeout:
 
235
                    client.CheckedOK(dbus_interface=client_interface)
 
236
                if options.start_checker:
 
237
                    client.StartChecker(dbus_interface=client_interface)
 
238
                if options.stop_checker:
 
239
                    client.StopChecker(dbus_interface=client_interface)
 
240
                if options.is_enabled:
 
241
                    sys.exit(0 if client.Get(client_interface,
 
242
                                             u"Enabled",
 
243
                                             dbus_interface=dbus.PROPERTIES_IFACE)
 
244
                             else 1)
 
245
                if options.checker:
 
246
                    client.Set(client_interface, u"Checker", options.checker,
 
247
                               dbus_interface=dbus.PROPERTIES_IFACE)
 
248
                if options.host:
 
249
                    client.Set(client_interface, u"Host", options.host,
 
250
                               dbus_interface=dbus.PROPERTIES_IFACE)
 
251
                if options.interval:
 
252
                    client.Set(client_interface, u"Interval",
 
253
                               timedelta_to_milliseconds
 
254
                               (string_to_delta(options.interval)),
 
255
                               dbus_interface=dbus.PROPERTIES_IFACE)
 
256
                if options.timeout:
 
257
                    client.Set(client_interface, u"Timeout",
 
258
                               timedelta_to_milliseconds(string_to_delta
 
259
                                                         (options.timeout)),
 
260
                               dbus_interface=dbus.PROPERTIES_IFACE)
 
261
                if options.secret:
 
262
                    client.Set(client_interface, u"Secret",
 
263
                               dbus.ByteArray(open(options.secret, u'rb').read()),
 
264
                               dbus_interface=dbus.PROPERTIES_IFACE)
 
265
                if options.approve:
 
266
                    client.Approve(dbus.Boolean(True), dbus_interface=client_interface)
 
267
                if options.deny:
 
268
                    client.Approve(dbus.Boolean(False), dbus_interface=client_interface)
 
269
 
 
270
if __name__ == '__main__':
 
271
    main()