/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()
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 list of clients to process
199
	clients=[]
200
201
        if options.all or not client_names:
202
            clients = (bus.get_object(busname, path) for path in mandos_clients.iterkeys())
203
        else:
204
            for name in client_names:
205
                for path, client in mandos_clients.iteritems():
24.1.164 by Björn Påhlsson
merge
206
                    if client['Name'] == name:
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
207
                        client_objc = bus.get_object(busname, path)
208
                        clients.append(client_objc)
209
                        break
210
                else:
211
                    print >> sys.stderr, "Client not found on server: %r" % name
212
                    sys.exit(1)
213
            
214
	if not has_actions(options) and clients:
215
	    if options.verbose:
24.1.164 by Björn Påhlsson
merge
216
	        keywords = ('Name', 'Enabled', 'Timeout', 'LastCheckedOK',
217
	                    'Created', 'Interval', 'Host', 'Fingerprint',
218
	                    'CheckerRunning', 'LastEnabled', 'Checker')
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
219
            else:
220
                keywords = defaultkeywords
221
                
222
	    print_clients(mandos_clients.values(), keywords)
223
        else:
224
            # Process each client in the list by all selected options
225
            for client in clients:
226
                if options.remove:
227
                    mandos_serv.RemoveClient(client.__dbus_object_path__)
228
                if options.enable:
229
                    client.Enable(dbus_interface=client_interface)
230
                if options.disable:
231
                    client.Disable(dbus_interface=client_interface)
232
                if options.bump_timeout:
233
                    client.CheckedOK(dbus_interface=client_interface)
234
                if options.start_checker:
235
                    client.StartChecker(dbus_interface=client_interface)
236
                if options.stop_checker:
237
                    client.StopChecker(dbus_interface=client_interface)
238
                if options.is_enabled:
239
                    sys.exit(0 if client.Get(client_interface,
24.1.164 by Björn Påhlsson
merge
240
                                             u"Enabled",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
241
                                             dbus_interface=dbus.PROPERTIES_IFACE)
242
                             else 1)
243
                if options.checker:
24.1.164 by Björn Påhlsson
merge
244
                    client.Set(client_interface, u"Checker", options.checker,
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
245
                               dbus_interface=dbus.PROPERTIES_IFACE)
246
                if options.host:
24.1.164 by Björn Påhlsson
merge
247
                    client.Set(client_interface, u"Host", options.host,
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.interval:
24.1.164 by Björn Påhlsson
merge
250
                    client.Set(client_interface, u"Interval",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
251
                               timedelta_to_milliseconds
252
                               (string_to_delta(options.interval)),
253
                               dbus_interface=dbus.PROPERTIES_IFACE)
254
                if options.timeout:
24.1.164 by Björn Påhlsson
merge
255
                    client.Set(client_interface, u"Timeout",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
256
                               timedelta_to_milliseconds(string_to_delta
257
                                                         (options.timeout)),
258
                               dbus_interface=dbus.PROPERTIES_IFACE)
259
                if options.secret:
24.1.164 by Björn Påhlsson
merge
260
                    client.Set(client_interface, u"Secret",
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
261
                               dbus.ByteArray(open(options.secret, u'rb').read()),
262
                               dbus_interface=dbus.PROPERTIES_IFACE)
263
                if options.approve:
264
                    client.Approve(dbus.Boolean(True), dbus_interface=client_interface)
265
                if options.deny:
266
                    client.Approve(dbus.Boolean(False), dbus_interface=client_interface)
267
268
if __name__ == '__main__':
269
    main()