126
126
a sensible number of times
127
127
group: D-Bus Entry Group
128
128
server: D-Bus Server
129
bus: dbus.SystemBus()
131
130
def __init__(self, interface = avahi.IF_UNSPEC, name = None,
132
131
servicetype = None, port = None, TXT = None,
133
132
domain = u"", host = u"", max_renames = 32768,
134
protocol = avahi.PROTO_UNSPEC, bus = None):
133
protocol = avahi.PROTO_UNSPEC):
135
134
self.interface = interface
137
136
self.type = servicetype
170
168
"""Derived from the Avahi example code"""
171
169
if self.group is None:
172
170
self.group = dbus.Interface(
173
self.bus.get_object(avahi.DBUS_NAME,
174
self.server.EntryGroupNew()),
171
bus.get_object(avahi.DBUS_NAME,
172
self.server.EntryGroupNew()),
175
173
avahi.DBUS_INTERFACE_ENTRY_GROUP)
176
174
self.group.connect_to_signal('StateChanged',
177
175
self.entry_group_state_changed)
216
214
"""Derived from the Avahi example code"""
217
215
if self.server is None:
218
216
self.server = dbus.Interface(
219
self.bus.get_object(avahi.DBUS_NAME,
220
avahi.DBUS_PATH_SERVER),
217
bus.get_object(avahi.DBUS_NAME,
218
avahi.DBUS_PATH_SERVER),
221
219
avahi.DBUS_INTERFACE_SERVER)
222
220
self.server.connect_to_signal(u"StateChanged",
223
221
self.server_state_changed)
313
311
def enable(self):
314
312
"""Start this client's checker and timeout hooks"""
315
if getattr(self, u"enabled", False):
318
313
self.last_enabled = datetime.datetime.utcnow()
319
314
# Schedule a new checker to be started an 'interval' from now,
320
315
# and every interval from then on.
481
476
"""A Client class using D-Bus
484
dbus_object_path: dbus.ObjectPath
485
bus: dbus.SystemBus()
479
dbus_object_path: dbus.ObjectPath ; only set if self.use_dbus
487
481
# dbus.service.Object doesn't use super(), so we can't either.
489
def __init__(self, bus = None, *args, **kwargs):
483
def __init__(self, *args, **kwargs):
491
484
Client.__init__(self, *args, **kwargs)
492
485
# Only now, when this client is initialized, can it show up on
494
487
self.dbus_object_path = (dbus.ObjectPath
496
489
+ self.name.replace(u".", u"_")))
497
dbus.service.Object.__init__(self, self.bus,
490
dbus.service.Object.__init__(self, bus,
498
491
self.dbus_object_path)
898
891
class ForkingMixInWithPipe(socketserver.ForkingMixIn, object):
899
"""Like socketserver.ForkingMixIn, but also pass a pipe."""
892
"""Like socketserver.ForkingMixIn, but also pass a pipe.
894
Assumes a gobject.MainLoop event loop.
900
896
def process_request(self, request, client_address):
901
897
"""Overrides and wraps the original process_request().
906
902
super(ForkingMixInWithPipe,
907
903
self).process_request(request, client_address)
908
904
os.close(self.pipe[1]) # close write end
909
self.add_pipe(self.pipe[0])
910
def add_pipe(self, pipe):
905
# Call "handle_ipc" for both data and EOF events
906
gobject.io_add_watch(self.pipe[0],
907
gobject.IO_IN | gobject.IO_HUP,
909
def handle_ipc(source, condition):
911
910
"""Dummy function; override as necessary"""
915
915
class IPv6_TCPServer(ForkingMixInWithPipe,
920
920
enabled: Boolean; whether this server is activated yet
921
921
interface: None or a network interface name (string)
922
922
use_ipv6: Boolean; to use IPv6 or not
924
clients: set of Client objects
925
gnutls_priority GnuTLS priority string
926
use_dbus: Boolean; to emit D-Bus signals or not
924
928
def __init__(self, server_address, RequestHandlerClass,
925
interface=None, use_ipv6=True):
929
interface=None, use_ipv6=True, clients=None,
930
gnutls_priority=None, use_dbus=True):
926
932
self.interface = interface
928
934
self.address_family = socket.AF_INET6
935
self.clients = clients
936
self.use_dbus = use_dbus
937
self.gnutls_priority = gnutls_priority
929
938
socketserver.TCPServer.__init__(self, server_address,
930
939
RequestHandlerClass)
931
940
def server_bind(self):
933
942
to bind to an interface if one was specified, and also NOT to
934
943
bind to an address or port if they were not specified."""
935
944
if self.interface is not None:
936
if SO_BINDTODEVICE is None:
937
logger.error(u"SO_BINDTODEVICE does not exist;"
938
u" cannot bind to interface %s",
942
self.socket.setsockopt(socket.SOL_SOCKET,
946
except socket.error, error:
947
if error[0] == errno.EPERM:
948
logger.error(u"No permission to"
949
u" bind to interface %s",
951
elif error[0] == errno.ENOPROTOOPT:
952
logger.error(u"SO_BINDTODEVICE not available;"
953
u" cannot bind to interface %s",
946
self.socket.setsockopt(socket.SOL_SOCKET,
948
str(self.interface + u'\0'))
949
except socket.error, error:
950
if error[0] == errno.EPERM:
951
logger.error(u"No permission to"
952
u" bind to interface %s",
957
956
# Only bind(2) the socket if we really need to.
958
957
if self.server_address[0] or self.server_address[1]:
959
958
if not self.server_address[0]:
974
973
# (self.interface))
975
974
return socketserver.TCPServer.server_bind(self)
978
class MandosServer(IPv6_TCPServer):
982
clients: set of Client objects
983
gnutls_priority GnuTLS priority string
984
use_dbus: Boolean; to emit D-Bus signals or not
985
clients: set of Client objects
986
gnutls_priority GnuTLS priority string
987
use_dbus: Boolean; to emit D-Bus signals or not
989
Assumes a gobject.MainLoop event loop.
991
def __init__(self, server_address, RequestHandlerClass,
992
interface=None, use_ipv6=True, clients=None,
993
gnutls_priority=None, use_dbus=True):
995
self.clients = clients
996
if self.clients is None:
998
self.use_dbus = use_dbus
999
self.gnutls_priority = gnutls_priority
1000
IPv6_TCPServer.__init__(self, server_address,
1001
RequestHandlerClass,
1002
interface = interface,
1003
use_ipv6 = use_ipv6)
1004
975
def server_activate(self):
1005
976
if self.enabled:
1006
977
return socketserver.TCPServer.server_activate(self)
1007
978
def enable(self):
1008
979
self.enabled = True
1009
def add_pipe(self, pipe):
1010
# Call "handle_ipc" for both data and EOF events
1011
gobject.io_add_watch(pipe, gobject.IO_IN | gobject.IO_HUP,
1013
980
def handle_ipc(self, source, condition, file_objects={}):
1014
981
condition_names = {
1015
982
gobject.IO_IN: u"IN", # There is data to read.
1279
1246
global mandos_dbus_service
1280
1247
mandos_dbus_service = None
1282
tcp_server = MandosServer((server_settings[u"address"],
1283
server_settings[u"port"]),
1285
interface=server_settings[u"interface"],
1288
server_settings[u"priority"],
1250
tcp_server = IPv6_TCPServer((server_settings[u"address"],
1251
server_settings[u"port"]),
1254
server_settings[u"interface"],
1258
server_settings[u"priority"],
1290
1260
pidfilename = u"/var/run/mandos.pid"
1292
1262
pidfile = open(pidfilename, u"w")
1327
1297
(gnutls.library.functions
1328
1298
.gnutls_global_set_log_function(debug_gnutls))
1301
protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1302
service = AvahiService(name = server_settings[u"servicename"],
1303
servicetype = u"_mandos._tcp",
1304
protocol = protocol)
1305
if server_settings["interface"]:
1306
service.interface = (if_nametoindex
1307
(str(server_settings[u"interface"])))
1330
1309
global main_loop
1331
1311
# From the Avahi example code
1332
1312
DBusGMainLoop(set_as_default=True )
1333
1313
main_loop = gobject.MainLoop()
1335
1315
# End of Avahi example code
1337
1317
bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos", bus)
1338
protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1339
service = AvahiService(name = server_settings[u"servicename"],
1340
servicetype = u"_mandos._tcp",
1341
protocol = protocol, bus = bus)
1342
if server_settings["interface"]:
1343
service.interface = (if_nametoindex
1344
(str(server_settings[u"interface"])))
1346
1319
client_class = Client
1348
client_class = functools.partial(ClientDBus, bus = bus)
1349
tcp_server.clients.update(set(
1321
client_class = ClientDBus
1350
1323
client_class(name = section,
1351
1324
config= dict(client_config.items(section)))
1352
1325
for section in client_config.sections()))
1353
if not tcp_server.clients:
1354
1327
logger.warning(u"No clients defined")
1419
1392
@dbus.service.method(_interface, out_signature=u"ao")
1420
1393
def GetAllClients(self):
1422
return dbus.Array(c.dbus_object_path
1423
for c in tcp_server.clients)
1395
return dbus.Array(c.dbus_object_path for c in clients)
1425
1397
@dbus.service.method(_interface,
1426
1398
out_signature=u"a{oa{sv}}")
1429
1401
return dbus.Dictionary(
1430
1402
((c.dbus_object_path, c.GetAllProperties())
1431
for c in tcp_server.clients),
1432
1404
signature=u"oa{sv}")
1434
1406
@dbus.service.method(_interface, in_signature=u"o")
1435
1407
def RemoveClient(self, object_path):
1437
for c in tcp_server.clients:
1438
1410
if c.dbus_object_path == object_path:
1439
tcp_server.clients.remove(c)
1440
1412
c.remove_from_connection()
1441
1413
# Don't signal anything except ClientRemoved
1442
1414
c.disable(signal=False)