/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"
382 by Teddy Hogeborn
* mandos-ctl: Made work again after D-Bus API changes.
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)
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
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()
437 by Teddy Hogeborn
* mandos-ctl: Bug fix: only show properties of specifies clients.
164
        
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
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
            
437 by Teddy Hogeborn
* mandos-ctl: Bug fix: only show properties of specifies clients.
198
	# Compile dict of (clients: properties) to process
199
	clients={}
200
        
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
201
        if options.all or not client_names:
437 by Teddy Hogeborn
* mandos-ctl: Bug fix: only show properties of specifies clients.
202
            clients = dict((bus.get_object(busname, path), properties)
203
                           for path, properties in
204
                           mandos_clients.iteritems())
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
205
        else:
206
            for name in client_names:
207
                for path, client in mandos_clients.iteritems():
24.1.164 by Björn Påhlsson
merge
208
                    if client['Name'] == name:
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
209
                        client_objc = bus.get_object(busname, path)
437 by Teddy Hogeborn
* mandos-ctl: Bug fix: only show properties of specifies clients.
210
                        clients[client_objc] = client
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
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:
24.1.164 by Björn Påhlsson
merge
218
	        keywords = ('Name', 'Enabled', 'Timeout', 'LastCheckedOK',
219
	                    'Created', 'Interval', 'Host', 'Fingerprint',
220
	                    'CheckerRunning', 'LastEnabled', 'Checker')
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
221
            else:
222
                keywords = defaultkeywords
223
                
437 by Teddy Hogeborn
* mandos-ctl: Bug fix: only show properties of specifies clients.
224
	    print_clients(clients.values(), keywords)
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
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,
24.1.164 by Björn Påhlsson
merge
242
                                             u"Enabled",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
243
                                             dbus_interface=dbus.PROPERTIES_IFACE)
244
                             else 1)
245
                if options.checker:
24.1.164 by Björn Påhlsson
merge
246
                    client.Set(client_interface, u"Checker", options.checker,
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
247
                               dbus_interface=dbus.PROPERTIES_IFACE)
248
                if options.host:
24.1.164 by Björn Påhlsson
merge
249
                    client.Set(client_interface, u"Host", options.host,
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
250
                               dbus_interface=dbus.PROPERTIES_IFACE)
251
                if options.interval:
24.1.164 by Björn Påhlsson
merge
252
                    client.Set(client_interface, u"Interval",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
253
                               timedelta_to_milliseconds
254
                               (string_to_delta(options.interval)),
255
                               dbus_interface=dbus.PROPERTIES_IFACE)
256
                if options.timeout:
24.1.164 by Björn Påhlsson
merge
257
                    client.Set(client_interface, u"Timeout",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
258
                               timedelta_to_milliseconds(string_to_delta
259
                                                         (options.timeout)),
260
                               dbus_interface=dbus.PROPERTIES_IFACE)
261
                if options.secret:
24.1.164 by Björn Påhlsson
merge
262
                    client.Set(client_interface, u"Secret",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
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()