/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 = {
240 by Teddy Hogeborn
Merge "mandos-list" from belorn.
16
    'name': u'Name',
17
    'enabled': u'Enabled',
18
    'timeout': u'Timeout',
19
    'last_checked_ok': u'Last Successful Check',
20
    'created': u'Created',
21
    'interval': u'Interval',
22
    'host': u'Host',
23
    'fingerprint': u'Fingerprint',
24
    'checker_running': u'Check Is Running',
25
    'last_enabled': u'Last Enabled',
26
    'checker': u'Checker',
24.1.116 by Björn Påhlsson
added a mandos list client program
27
    }
412 by Teddy Hogeborn
* mandos-ctl (defaultkeywords): Removed "checker".
28
defaultkeywords = ('name', 'enabled', 'timeout', 'last_checked_ok')
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]),
24.1.121 by Björn Påhlsson
mandos-ctl: Added support for all client calls
103
                                  max(len(valuetostring(client[key], key))
24.1.118 by Björn Påhlsson
Added enable/disable
104
                                      for client in
24.1.121 by Björn Påhlsson
mandos-ctl: Added support for all client calls
105
                                      clients))
24.1.118 by Björn Påhlsson
Added enable/disable
106
                              for key in keywords)
382 by Teddy Hogeborn
* mandos-ctl: Made work again after D-Bus API changes.
107
    # Print header line
355 by Teddy Hogeborn
* mandos: White-space fixes only.
108
    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
109
    for client in clients:
110
        print format_string % tuple(valuetostring(client[key], key)
24.1.118 by Björn Påhlsson
Added enable/disable
111
                                    for key in keywords)
24.1.163 by Björn Påhlsson
mandos-client: Added never ending loop for --connect
112
def has_actions(options):
113
    return any((options.enable,
114
                options.disable,
115
                options.bump_timeout,
116
                options.start_checker,
117
                options.stop_checker,
118
                options.is_enabled,
119
                options.remove,
120
                options.checker is not None,
121
                options.timeout is not None,
122
                options.interval is not None,
123
                options.host is not None,
124
                options.secret is not None,
125
                options.approve,
126
                options.deny))
127
        
128
def main():
129
	parser = OptionParser(version = "%%prog %s" % version)
130
	parser.add_option("-a", "--all", action="store_true",
131
	                  help="Select all clients")
132
	parser.add_option("-v", "--verbose", action="store_true",
133
	                  help="Print all fields")
134
	parser.add_option("-e", "--enable", action="store_true",
135
	                  help="Enable client")
136
	parser.add_option("-d", "--disable", action="store_true",
137
	                  help="disable client")
138
	parser.add_option("-b", "--bump-timeout", action="store_true",
139
	                  help="Bump timeout for client")
140
	parser.add_option("--start-checker", action="store_true",
141
	                  help="Start checker for client")
142
	parser.add_option("--stop-checker", action="store_true",
143
	                  help="Stop checker for client")
144
	parser.add_option("-V", "--is-enabled", action="store_true",
145
	                  help="Check if client is enabled")
146
	parser.add_option("-r", "--remove", action="store_true",
147
	                  help="Remove client")
148
	parser.add_option("-c", "--checker", type="string",
149
	                  help="Set checker command for client")
150
	parser.add_option("-t", "--timeout", type="string",
151
	                  help="Set timeout for client")
152
	parser.add_option("-i", "--interval", type="string",
153
	                  help="Set checker interval for client")
154
	parser.add_option("-H", "--host", type="string",
155
	                  help="Set host for client")
156
	parser.add_option("-s", "--secret", type="string",
157
	                  help="Set password blob (file) for client")
158
	parser.add_option("-A", "--approve", action="store_true",
159
	                  help="Approve any current client request")
160
	parser.add_option("-D", "--deny", action="store_true",
161
	                  help="Deny any current client request")
162
	options, client_names = parser.parse_args()
163
164
        if has_actions(options) and not client_names and not options.all:
165
            parser.error('Options requires clients names or --all.')
166
        if options.verbose and has_actions(options):
167
            parser.error('Verbose option can only be used alone or with --all.')
168
        if options.all and not has_actions(options):
169
            parser.error('--all requires an action')
170
            
171
        try:
172
            bus = dbus.SystemBus()
173
            mandos_dbus_objc = bus.get_object(busname, server_path)
174
        except dbus.exceptions.DBusException:
175
            print >> sys.stderr, "Could not connect to Mandos server"
176
            sys.exit(1)
177
    
178
        mandos_serv = dbus.Interface(mandos_dbus_objc,
179
                                     dbus_interface = server_interface)
180
181
        #block stderr since dbus library prints to stderr
182
        null = os.open(os.path.devnull, os.O_RDWR)
183
        stderrcopy = os.dup(sys.stderr.fileno())
184
        os.dup2(null, sys.stderr.fileno())
185
        os.close(null)
186
        try:
187
            try:
188
                mandos_clients = mandos_serv.GetAllClientsWithProperties()
189
            finally:
190
                #restore stderr
191
                os.dup2(stderrcopy, sys.stderr.fileno())
192
                os.close(stderrcopy)
193
        except dbus.exceptions.DBusException, e:
194
            print >> sys.stderr, "Access denied: Accessing mandos server through dbus."
195
            sys.exit(1)
196
            
197
	# Compile list of clients to process
198
	clients=[]
199
200
        if options.all or not client_names:
201
            clients = (bus.get_object(busname, path) for path in mandos_clients.iterkeys())
202
        else:
203
            for name in client_names:
204
                for path, client in mandos_clients.iteritems():
205
                    if client['name'] == name:
206
                        client_objc = bus.get_object(busname, path)
207
                        clients.append(client_objc)
208
                        break
209
                else:
210
                    print >> sys.stderr, "Client not found on server: %r" % name
211
                    sys.exit(1)
212
            
213
	if not has_actions(options) and clients:
214
	    if options.verbose:
215
	        keywords = ('name', 'enabled', 'timeout', 'last_checked_ok',
216
	                    'created', 'interval', 'host', 'fingerprint',
217
	                    'checker_running', 'last_enabled', 'checker')
218
            else:
219
                keywords = defaultkeywords
220
                
221
	    print_clients(mandos_clients.values(), keywords)
222
        else:
223
            # Process each client in the list by all selected options
224
            for client in clients:
225
                if options.remove:
226
                    mandos_serv.RemoveClient(client.__dbus_object_path__)
227
                if options.enable:
228
                    client.Enable(dbus_interface=client_interface)
229
                if options.disable:
230
                    client.Disable(dbus_interface=client_interface)
231
                if options.bump_timeout:
232
                    client.CheckedOK(dbus_interface=client_interface)
233
                if options.start_checker:
234
                    client.StartChecker(dbus_interface=client_interface)
235
                if options.stop_checker:
236
                    client.StopChecker(dbus_interface=client_interface)
237
                if options.is_enabled:
238
                    sys.exit(0 if client.Get(client_interface,
239
                                             u"enabled",
240
                                             dbus_interface=dbus.PROPERTIES_IFACE)
241
                             else 1)
242
                if options.checker:
243
                    client.Set(client_interface, u"checker", options.checker,
244
                               dbus_interface=dbus.PROPERTIES_IFACE)
245
                if options.host:
246
                    client.Set(client_interface, u"host", options.host,
247
                               dbus_interface=dbus.PROPERTIES_IFACE)
248
                if options.interval:
249
                    client.Set(client_interface, u"interval",
250
                               timedelta_to_milliseconds
251
                               (string_to_delta(options.interval)),
252
                               dbus_interface=dbus.PROPERTIES_IFACE)
253
                if options.timeout:
254
                    client.Set(client_interface, u"timeout",
255
                               timedelta_to_milliseconds(string_to_delta
256
                                                         (options.timeout)),
257
                               dbus_interface=dbus.PROPERTIES_IFACE)
258
                if options.secret:
259
                    client.Set(client_interface, u"secret",
260
                               dbus.ByteArray(open(options.secret, u'rb').read()),
261
                               dbus_interface=dbus.PROPERTIES_IFACE)
262
                if options.approve:
263
                    client.Approve(dbus.Boolean(True), dbus_interface=client_interface)
264
                if options.deny:
265
                    client.Approve(dbus.Boolean(False), dbus_interface=client_interface)
266
267
if __name__ == '__main__':
268
    main()