/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk
24.1.116 by Björn Påhlsson
added a mandos list client program
1
#!/usr/bin/python
240 by Teddy Hogeborn
Merge "mandos-list" from belorn.
2
# -*- mode: python; coding: utf-8 -*-
24.1.116 by Björn Påhlsson
added a mandos list client program
3
24.1.121 by Björn Påhlsson
mandos-ctl: Added support for all client calls
4
from __future__ import division
24.1.119 by Björn Påhlsson
Added more method support for mandos clients through mandos-ctl
5
import sys
24.1.116 by Björn Påhlsson
added a mandos list client program
6
import dbus
7
from optparse import OptionParser
240 by Teddy Hogeborn
Merge "mandos-list" from belorn.
8
import locale
24.1.121 by Björn Påhlsson
mandos-ctl: Added support for all client calls
9
import datetime
10
import re
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
11
import os
240 by Teddy Hogeborn
Merge "mandos-list" from belorn.
12
13
locale.setlocale(locale.LC_ALL, u'')
24.1.116 by Björn Påhlsson
added a mandos list client program
14
15
tablewords = {
422 by Teddy Hogeborn
Rename all D-Bus properties to conform to D-Bus naming conventions;
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',
24.1.116 by Björn Påhlsson
added a mandos list client program
27
    }
422 by Teddy Hogeborn
Rename all D-Bus properties to conform to D-Bus naming conventions;
28
defaultkeywords = ('Name', 'Enabled', 'Timeout', 'LastCheckedOK')
24.1.130 by Björn Påhlsson
new domain name for d-bus
29
domain = 'se.bsnet.fukt'
30
busname = domain + '.Mandos'
31
server_path = '/'
32
server_interface = domain + '.Mandos'
33
client_interface = domain + '.Mandos.Client'
237.2.32 by Teddy Hogeborn
* Makefile (version): Changed to "1.0.14".
34
version = "1.0.14"
24.1.118 by Björn Påhlsson
Added enable/disable
35
382 by Teddy Hogeborn
* mandos-ctl: Made work again after D-Bus API changes.
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))
24.1.121 by Björn Påhlsson
mandos-ctl: Added support for all client calls
41
42
def milliseconds_to_string(ms):
43
    td = datetime.timedelta(0, 0, 0, ms)
382 by Teddy Hogeborn
* mandos-ctl: Made work again after D-Bus API changes.
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
                })
24.1.121 by Björn Påhlsson
mandos-ctl: Added support for all client calls
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
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
92
def print_clients(clients, keywords):
24.1.121 by Björn Påhlsson
mandos-ctl: Added support for all client calls
93
    def valuetostring(value, keyword):
94
        if type(value) is dbus.Boolean:
95
            return u"Yes" if value else u"No"
438 by Teddy Hogeborn
* mandos (Client.runtime_expansions): New attribute containing the
96
        if keyword in (u"Timeout", u"Interval"):
24.1.121 by Björn Påhlsson
mandos-ctl: Added support for all client calls
97
            return milliseconds_to_string(value)
98
        return unicode(value)
99
    
382 by Teddy Hogeborn
* mandos-ctl: Made work again after D-Bus API changes.
100
    # Create format string to print table rows
24.1.118 by Björn Påhlsson
Added enable/disable
101
    format_string = u' '.join(u'%%-%ds' %
102
                              max(len(tablewords[key]),
422 by Teddy Hogeborn
Rename all D-Bus properties to conform to D-Bus naming conventions;
103
                                  max(len(valuetostring(client[key],
104
                                                        key))
24.1.118 by Björn Påhlsson
Added enable/disable
105
                                      for client in
24.1.121 by Björn Påhlsson
mandos-ctl: Added support for all client calls
106
                                      clients))
24.1.118 by Björn Påhlsson
Added enable/disable
107
                              for key in keywords)
382 by Teddy Hogeborn
* mandos-ctl: Made work again after D-Bus API changes.
108
    # Print header line
355 by Teddy Hogeborn
* mandos: White-space fixes only.
109
    print format_string % tuple(tablewords[key] for key in keywords)
24.1.121 by Björn Påhlsson
mandos-ctl: Added support for all client calls
110
    for client in clients:
111
        print format_string % tuple(valuetostring(client[key], key)
24.1.118 by Björn Påhlsson
Added enable/disable
112
                                    for key in keywords)
438 by Teddy Hogeborn
* mandos (Client.runtime_expansions): New attribute containing the
113
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
114
def has_actions(options):
115
    return any((options.enable,
116
                options.disable,
117
                options.bump_timeout,
118
                options.start_checker,
119
                options.stop_checker,
120
                options.is_enabled,
121
                options.remove,
122
                options.checker is not None,
123
                options.timeout is not None,
124
                options.interval is not None,
125
                options.host is not None,
126
                options.secret is not None,
127
                options.approve,
128
                options.deny))
129
        
130
def main():
131
	parser = OptionParser(version = "%%prog %s" % version)
132
	parser.add_option("-a", "--all", action="store_true",
133
	                  help="Select all clients")
134
	parser.add_option("-v", "--verbose", action="store_true",
135
	                  help="Print all fields")
136
	parser.add_option("-e", "--enable", action="store_true",
137
	                  help="Enable client")
138
	parser.add_option("-d", "--disable", action="store_true",
139
	                  help="disable client")
140
	parser.add_option("-b", "--bump-timeout", action="store_true",
141
	                  help="Bump timeout for client")
142
	parser.add_option("--start-checker", action="store_true",
143
	                  help="Start checker for client")
144
	parser.add_option("--stop-checker", action="store_true",
145
	                  help="Stop checker for client")
146
	parser.add_option("-V", "--is-enabled", action="store_true",
147
	                  help="Check if client is enabled")
148
	parser.add_option("-r", "--remove", action="store_true",
149
	                  help="Remove client")
150
	parser.add_option("-c", "--checker", type="string",
151
	                  help="Set checker command for client")
152
	parser.add_option("-t", "--timeout", type="string",
153
	                  help="Set timeout for client")
154
	parser.add_option("-i", "--interval", type="string",
155
	                  help="Set checker interval for client")
156
	parser.add_option("-H", "--host", type="string",
157
	                  help="Set host for client")
158
	parser.add_option("-s", "--secret", type="string",
159
	                  help="Set password blob (file) for client")
160
	parser.add_option("-A", "--approve", action="store_true",
161
	                  help="Approve any current client request")
162
	parser.add_option("-D", "--deny", action="store_true",
163
	                  help="Deny any current client request")
164
	options, client_names = parser.parse_args()
437 by Teddy Hogeborn
* mandos-ctl: Bug fix: only show properties of specifies clients.
165
        
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
166
        if has_actions(options) and not client_names and not options.all:
167
            parser.error('Options requires clients names or --all.')
168
        if options.verbose and has_actions(options):
169
            parser.error('Verbose option can only be used alone or with --all.')
170
        if options.all and not has_actions(options):
171
            parser.error('--all requires an action')
172
            
173
        try:
174
            bus = dbus.SystemBus()
175
            mandos_dbus_objc = bus.get_object(busname, server_path)
176
        except dbus.exceptions.DBusException:
177
            print >> sys.stderr, "Could not connect to Mandos server"
178
            sys.exit(1)
179
    
180
        mandos_serv = dbus.Interface(mandos_dbus_objc,
181
                                     dbus_interface = server_interface)
182
183
        #block stderr since dbus library prints to stderr
184
        null = os.open(os.path.devnull, os.O_RDWR)
185
        stderrcopy = os.dup(sys.stderr.fileno())
186
        os.dup2(null, sys.stderr.fileno())
187
        os.close(null)
188
        try:
189
            try:
190
                mandos_clients = mandos_serv.GetAllClientsWithProperties()
191
            finally:
192
                #restore stderr
193
                os.dup2(stderrcopy, sys.stderr.fileno())
194
                os.close(stderrcopy)
195
        except dbus.exceptions.DBusException, e:
196
            print >> sys.stderr, "Access denied: Accessing mandos server through dbus."
197
            sys.exit(1)
198
            
437 by Teddy Hogeborn
* mandos-ctl: Bug fix: only show properties of specifies clients.
199
	# Compile dict of (clients: properties) to process
200
	clients={}
201
        
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
202
        if options.all or not client_names:
437 by Teddy Hogeborn
* mandos-ctl: Bug fix: only show properties of specifies clients.
203
            clients = dict((bus.get_object(busname, path), properties)
204
                           for path, properties in
205
                           mandos_clients.iteritems())
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
206
        else:
207
            for name in client_names:
208
                for path, client in mandos_clients.iteritems():
24.1.164 by Björn Påhlsson
merge
209
                    if client['Name'] == name:
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
210
                        client_objc = bus.get_object(busname, path)
437 by Teddy Hogeborn
* mandos-ctl: Bug fix: only show properties of specifies clients.
211
                        clients[client_objc] = client
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
212
                        break
213
                else:
214
                    print >> sys.stderr, "Client not found on server: %r" % name
215
                    sys.exit(1)
216
            
217
	if not has_actions(options) and clients:
218
	    if options.verbose:
24.1.164 by Björn Påhlsson
merge
219
	        keywords = ('Name', 'Enabled', 'Timeout', 'LastCheckedOK',
220
	                    'Created', 'Interval', 'Host', 'Fingerprint',
221
	                    'CheckerRunning', 'LastEnabled', 'Checker')
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
222
            else:
223
                keywords = defaultkeywords
224
                
437 by Teddy Hogeborn
* mandos-ctl: Bug fix: only show properties of specifies clients.
225
	    print_clients(clients.values(), keywords)
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
226
        else:
227
            # Process each client in the list by all selected options
228
            for client in clients:
229
                if options.remove:
230
                    mandos_serv.RemoveClient(client.__dbus_object_path__)
231
                if options.enable:
232
                    client.Enable(dbus_interface=client_interface)
233
                if options.disable:
234
                    client.Disable(dbus_interface=client_interface)
235
                if options.bump_timeout:
236
                    client.CheckedOK(dbus_interface=client_interface)
237
                if options.start_checker:
238
                    client.StartChecker(dbus_interface=client_interface)
239
                if options.stop_checker:
240
                    client.StopChecker(dbus_interface=client_interface)
241
                if options.is_enabled:
242
                    sys.exit(0 if client.Get(client_interface,
24.1.164 by Björn Påhlsson
merge
243
                                             u"Enabled",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
244
                                             dbus_interface=dbus.PROPERTIES_IFACE)
245
                             else 1)
246
                if options.checker:
24.1.164 by Björn Påhlsson
merge
247
                    client.Set(client_interface, u"Checker", options.checker,
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
248
                               dbus_interface=dbus.PROPERTIES_IFACE)
249
                if options.host:
24.1.164 by Björn Påhlsson
merge
250
                    client.Set(client_interface, u"Host", options.host,
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
251
                               dbus_interface=dbus.PROPERTIES_IFACE)
252
                if options.interval:
24.1.164 by Björn Påhlsson
merge
253
                    client.Set(client_interface, u"Interval",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
254
                               timedelta_to_milliseconds
255
                               (string_to_delta(options.interval)),
256
                               dbus_interface=dbus.PROPERTIES_IFACE)
257
                if options.timeout:
24.1.164 by Björn Påhlsson
merge
258
                    client.Set(client_interface, u"Timeout",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
259
                               timedelta_to_milliseconds(string_to_delta
260
                                                         (options.timeout)),
261
                               dbus_interface=dbus.PROPERTIES_IFACE)
262
                if options.secret:
24.1.164 by Björn Påhlsson
merge
263
                    client.Set(client_interface, u"Secret",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
264
                               dbus.ByteArray(open(options.secret, u'rb').read()),
265
                               dbus_interface=dbus.PROPERTIES_IFACE)
266
                if options.approve:
267
                    client.Approve(dbus.Boolean(True), dbus_interface=client_interface)
268
                if options.deny:
269
                    client.Approve(dbus.Boolean(False), dbus_interface=client_interface)
270
271
if __name__ == '__main__':
272
    main()