247
240
last_checked_ok: datetime.datetime(); (UTC) or None
248
241
timeout: datetime.timedelta(); How long from last_checked_ok
249
until this client is disabled
242
until this client is invalid
250
243
interval: datetime.timedelta(); How often to start a new checker
251
244
disable_hook: If set, called by disable() as disable_hook(self)
252
245
checker: subprocess.Popen(); a running checker process used
253
246
to see if the client lives.
254
247
'None' if no process is running.
255
248
checker_initiator_tag: a gobject event source tag, or None
256
disable_initiator_tag: - '' -
249
disable_initiator_tag: - '' -
257
250
checker_callback_tag: - '' -
258
251
checker_command: string; External command which is run to check if
259
252
client lives. %() expansions are done at
260
253
runtime with vars(self) as dict, so that for
261
254
instance %(name)s can be used in the command.
262
255
current_checker_command: string; current running checker_command
263
approved_delay: datetime.timedelta(); Time to wait for approval
264
_approved: bool(); 'None' if not yet approved/disapproved
265
approved_duration: datetime.timedelta(); Duration of one approval
269
def _timedelta_to_milliseconds(td):
270
"Convert a datetime.timedelta() to milliseconds"
271
return ((td.days * 24 * 60 * 60 * 1000)
272
+ (td.seconds * 1000)
273
+ (td.microseconds // 1000))
259
def _datetime_to_milliseconds(dt):
260
"Convert a datetime.datetime() to milliseconds"
261
return ((dt.days * 24 * 60 * 60 * 1000)
262
+ (dt.seconds * 1000)
263
+ (dt.microseconds // 1000))
275
265
def timeout_milliseconds(self):
276
266
"Return the 'timeout' attribute in milliseconds"
277
return self._timedelta_to_milliseconds(self.timeout)
267
return self._datetime_to_milliseconds(self.timeout)
279
269
def interval_milliseconds(self):
280
270
"Return the 'interval' attribute in milliseconds"
281
return self._timedelta_to_milliseconds(self.interval)
283
def approved_delay_milliseconds(self):
284
return self._timedelta_to_milliseconds(self.approved_delay)
271
return self._datetime_to_milliseconds(self.interval)
286
273
def __init__(self, name = None, disable_hook=None, config=None):
287
274
"""Note: the 'checker' key in 'config' sets the
323
309
self.checker_command = config[u"checker"]
324
310
self.current_checker_command = None
325
311
self.last_connect = None
326
self.approvals_pending = 0
327
self._approved = None
328
self.approved_by_default = config.get(u"approved_by_default",
330
self.approved_delay = string_to_delta(
331
config[u"approved_delay"])
332
self.approved_duration = string_to_delta(
333
config[u"approved_duration"])
334
self.changedstate = multiprocessing_manager.Condition(multiprocessing_manager.Lock())
336
def send_changedstate(self):
337
self.changedstate.acquire()
338
self.changedstate.notify_all()
339
self.changedstate.release()
341
313
def enable(self):
342
314
"""Start this client's checker and timeout hooks"""
343
315
if getattr(self, u"enabled", False):
344
316
# Already enabled
346
self.send_changedstate()
347
318
self.last_enabled = datetime.datetime.utcnow()
348
319
# Schedule a new checker to be started an 'interval' from now,
349
320
# and every interval from then on.
350
321
self.checker_initiator_tag = (gobject.timeout_add
351
322
(self.interval_milliseconds(),
352
323
self.start_checker))
324
# Also start a new checker *right now*.
353
326
# Schedule a disable() when 'timeout' has passed
354
327
self.disable_initiator_tag = (gobject.timeout_add
355
328
(self.timeout_milliseconds(),
357
330
self.enabled = True
358
# Also start a new checker *right now*.
361
def disable(self, quiet=True):
362
333
"""Disable this client."""
363
334
if not getattr(self, "enabled", False):
366
self.send_changedstate()
368
logger.info(u"Disabling client %s", self.name)
336
logger.info(u"Disabling client %s", self.name)
369
337
if getattr(self, u"disable_initiator_tag", False):
370
338
gobject.source_remove(self.disable_initiator_tag)
371
339
self.disable_initiator_tag = None
495
458
logger.debug(u"Stopping checker for %(name)s", vars(self))
497
460
os.kill(self.checker.pid, signal.SIGTERM)
499
462
#if self.checker.poll() is None:
500
463
# os.kill(self.checker.pid, signal.SIGKILL)
501
464
except OSError, error:
502
465
if error.errno != errno.ESRCH: # No such process
504
467
self.checker = None
506
def dbus_service_property(dbus_interface, signature=u"v",
507
access=u"readwrite", byte_arrays=False):
508
"""Decorators for marking methods of a DBusObjectWithProperties to
509
become properties on the D-Bus.
511
The decorated method will be called with no arguments by "Get"
512
and with one argument by "Set".
514
The parameters, where they are supported, are the same as
515
dbus.service.method, except there is only "signature", since the
516
type from Get() and the type sent to Set() is the same.
518
# Encoding deeply encoded byte arrays is not supported yet by the
519
# "Set" method, so we fail early here:
520
if byte_arrays and signature != u"ay":
521
raise ValueError(u"Byte arrays not supported for non-'ay'"
522
u" signature %r" % signature)
524
func._dbus_is_property = True
525
func._dbus_interface = dbus_interface
526
func._dbus_signature = signature
527
func._dbus_access = access
528
func._dbus_name = func.__name__
529
if func._dbus_name.endswith(u"_dbus_property"):
530
func._dbus_name = func._dbus_name[:-14]
531
func._dbus_get_args_options = {u'byte_arrays': byte_arrays }
536
class DBusPropertyException(dbus.exceptions.DBusException):
537
"""A base class for D-Bus property-related exceptions
539
def __unicode__(self):
540
return unicode(str(self))
543
class DBusPropertyAccessException(DBusPropertyException):
544
"""A property's access permissions disallows an operation.
549
class DBusPropertyNotFound(DBusPropertyException):
550
"""An attempt was made to access a non-existing property.
555
class DBusObjectWithProperties(dbus.service.Object):
556
"""A D-Bus object with properties.
558
Classes inheriting from this can use the dbus_service_property
559
decorator to expose methods as D-Bus properties. It exposes the
560
standard Get(), Set(), and GetAll() methods on the D-Bus.
564
def _is_dbus_property(obj):
565
return getattr(obj, u"_dbus_is_property", False)
567
def _get_all_dbus_properties(self):
568
"""Returns a generator of (name, attribute) pairs
570
return ((prop._dbus_name, prop)
572
inspect.getmembers(self, self._is_dbus_property))
574
def _get_dbus_property(self, interface_name, property_name):
575
"""Returns a bound method if one exists which is a D-Bus
576
property with the specified name and interface.
578
for name in (property_name,
579
property_name + u"_dbus_property"):
580
prop = getattr(self, name, None)
582
or not self._is_dbus_property(prop)
583
or prop._dbus_name != property_name
584
or (interface_name and prop._dbus_interface
585
and interface_name != prop._dbus_interface)):
589
raise DBusPropertyNotFound(self.dbus_object_path + u":"
590
+ interface_name + u"."
593
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ss",
595
def Get(self, interface_name, property_name):
596
"""Standard D-Bus property Get() method, see D-Bus standard.
598
prop = self._get_dbus_property(interface_name, property_name)
599
if prop._dbus_access == u"write":
600
raise DBusPropertyAccessException(property_name)
602
if not hasattr(value, u"variant_level"):
604
return type(value)(value, variant_level=value.variant_level+1)
606
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ssv")
607
def Set(self, interface_name, property_name, value):
608
"""Standard D-Bus property Set() method, see D-Bus standard.
610
prop = self._get_dbus_property(interface_name, property_name)
611
if prop._dbus_access == u"read":
612
raise DBusPropertyAccessException(property_name)
613
if prop._dbus_get_args_options[u"byte_arrays"]:
614
# The byte_arrays option is not supported yet on
615
# signatures other than "ay".
616
if prop._dbus_signature != u"ay":
618
value = dbus.ByteArray(''.join(unichr(byte)
622
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"s",
623
out_signature=u"a{sv}")
624
def GetAll(self, interface_name):
625
"""Standard D-Bus property GetAll() method, see D-Bus
628
Note: Will not include properties with access="write".
631
for name, prop in self._get_all_dbus_properties():
633
and interface_name != prop._dbus_interface):
634
# Interface non-empty but did not match
636
# Ignore write-only properties
637
if prop._dbus_access == u"write":
640
if not hasattr(value, u"variant_level"):
643
all[name] = type(value)(value, variant_level=
644
value.variant_level+1)
645
return dbus.Dictionary(all, signature=u"sv")
647
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
649
path_keyword='object_path',
650
connection_keyword='connection')
651
def Introspect(self, object_path, connection):
652
"""Standard D-Bus method, overloaded to insert property tags.
654
xmlstring = dbus.service.Object.Introspect(self, object_path,
657
document = xml.dom.minidom.parseString(xmlstring)
658
def make_tag(document, name, prop):
659
e = document.createElement(u"property")
660
e.setAttribute(u"name", name)
661
e.setAttribute(u"type", prop._dbus_signature)
662
e.setAttribute(u"access", prop._dbus_access)
664
for if_tag in document.getElementsByTagName(u"interface"):
665
for tag in (make_tag(document, name, prop)
667
in self._get_all_dbus_properties()
668
if prop._dbus_interface
669
== if_tag.getAttribute(u"name")):
670
if_tag.appendChild(tag)
671
# Add the names to the return values for the
672
# "org.freedesktop.DBus.Properties" methods
673
if (if_tag.getAttribute(u"name")
674
== u"org.freedesktop.DBus.Properties"):
675
for cn in if_tag.getElementsByTagName(u"method"):
676
if cn.getAttribute(u"name") == u"Get":
677
for arg in cn.getElementsByTagName(u"arg"):
678
if (arg.getAttribute(u"direction")
680
arg.setAttribute(u"name", u"value")
681
elif cn.getAttribute(u"name") == u"GetAll":
682
for arg in cn.getElementsByTagName(u"arg"):
683
if (arg.getAttribute(u"direction")
685
arg.setAttribute(u"name", u"props")
686
xmlstring = document.toxml(u"utf-8")
688
except (AttributeError, xml.dom.DOMException,
689
xml.parsers.expat.ExpatError), error:
690
logger.error(u"Failed to override Introspection method",
695
class ClientDBus(Client, DBusObjectWithProperties):
469
def still_valid(self):
470
"""Has the timeout not yet passed for this client?"""
471
if not getattr(self, u"enabled", False):
473
now = datetime.datetime.utcnow()
474
if self.last_checked_ok is None:
475
return now < (self.created + self.timeout)
477
return now < (self.last_checked_ok + self.timeout)
480
class ClientDBus(Client, dbus.service.Object):
696
481
"""A Client class using D-Bus
614
# GetAllProperties - method
615
@dbus.service.method(_interface, out_signature=u"a{sv}")
616
def GetAllProperties(self):
618
return dbus.Dictionary({
619
dbus.String(u"name"):
620
dbus.String(self.name, variant_level=1),
621
dbus.String(u"fingerprint"):
622
dbus.String(self.fingerprint, variant_level=1),
623
dbus.String(u"host"):
624
dbus.String(self.host, variant_level=1),
625
dbus.String(u"created"):
626
self._datetime_to_dbus(self.created,
628
dbus.String(u"last_enabled"):
629
(self._datetime_to_dbus(self.last_enabled,
631
if self.last_enabled is not None
632
else dbus.Boolean(False, variant_level=1)),
633
dbus.String(u"enabled"):
634
dbus.Boolean(self.enabled, variant_level=1),
635
dbus.String(u"last_checked_ok"):
636
(self._datetime_to_dbus(self.last_checked_ok,
638
if self.last_checked_ok is not None
639
else dbus.Boolean (False, variant_level=1)),
640
dbus.String(u"timeout"):
641
dbus.UInt64(self.timeout_milliseconds(),
643
dbus.String(u"interval"):
644
dbus.UInt64(self.interval_milliseconds(),
646
dbus.String(u"checker"):
647
dbus.String(self.checker_command,
649
dbus.String(u"checker_running"):
650
dbus.Boolean(self.checker is not None,
652
dbus.String(u"object_path"):
653
dbus.ObjectPath(self.dbus_object_path,
657
# IsStillValid - method
658
@dbus.service.method(_interface, out_signature=u"b")
659
def IsStillValid(self):
660
return self.still_valid()
851
662
# PropertyChanged - signal
852
663
@dbus.service.signal(_interface, signature=u"sv")
853
664
def PropertyChanged(self, property, value):
668
# ReceivedSecret - signal
858
669
@dbus.service.signal(_interface)
670
def ReceivedSecret(self):
863
674
# Rejected - signal
864
@dbus.service.signal(_interface, signature=u"s")
865
def Rejected(self, reason):
869
# NeedApproval - signal
870
@dbus.service.signal(_interface, signature=u"db")
871
def NeedApproval(self, timeout, default):
878
@dbus.service.method(_interface, in_signature=u"b")
879
def Approve(self, value):
883
@dbus.service.method(_interface)
885
return self.checked_ok()
675
@dbus.service.signal(_interface)
680
# SetChecker - method
681
@dbus.service.method(_interface, in_signature=u"s")
682
def SetChecker(self, checker):
683
"D-Bus setter method"
684
self.checker_command = checker
686
self.PropertyChanged(dbus.String(u"checker"),
687
dbus.String(self.checker_command,
691
@dbus.service.method(_interface, in_signature=u"s")
692
def SetHost(self, host):
693
"D-Bus setter method"
696
self.PropertyChanged(dbus.String(u"host"),
697
dbus.String(self.host, variant_level=1))
699
# SetInterval - method
700
@dbus.service.method(_interface, in_signature=u"t")
701
def SetInterval(self, milliseconds):
702
self.interval = datetime.timedelta(0, 0, 0, milliseconds)
704
self.PropertyChanged(dbus.String(u"interval"),
705
(dbus.UInt64(self.interval_milliseconds(),
709
@dbus.service.method(_interface, in_signature=u"ay",
711
def SetSecret(self, secret):
712
"D-Bus setter method"
713
self.secret = str(secret)
715
# SetTimeout - method
716
@dbus.service.method(_interface, in_signature=u"t")
717
def SetTimeout(self, milliseconds):
718
self.timeout = datetime.timedelta(0, 0, 0, milliseconds)
720
self.PropertyChanged(dbus.String(u"timeout"),
721
(dbus.UInt64(self.timeout_milliseconds(),
887
724
# Enable - method
888
725
@dbus.service.method(_interface)
907
744
def StopChecker(self):
908
745
self.stop_checker()
912
# approved_pending - property
913
@dbus_service_property(_interface, signature=u"b", access=u"read")
914
def approved_pending_dbus_property(self):
915
return dbus.Boolean(bool(self.approvals_pending))
917
# approved_by_default - property
918
@dbus_service_property(_interface, signature=u"b",
920
def approved_by_default_dbus_property(self):
921
return dbus.Boolean(self.approved_by_default)
923
# approved_delay - property
924
@dbus_service_property(_interface, signature=u"t",
926
def approved_delay_dbus_property(self):
927
return dbus.UInt64(self.approved_delay_milliseconds())
929
# approved_duration - property
930
@dbus_service_property(_interface, signature=u"t",
932
def approved_duration_dbus_property(self):
933
return dbus.UInt64(self._timedelta_to_milliseconds(
934
self.approved_duration))
937
@dbus_service_property(_interface, signature=u"s", access=u"read")
938
def name_dbus_property(self):
939
return dbus.String(self.name)
941
# fingerprint - property
942
@dbus_service_property(_interface, signature=u"s", access=u"read")
943
def fingerprint_dbus_property(self):
944
return dbus.String(self.fingerprint)
947
@dbus_service_property(_interface, signature=u"s",
949
def host_dbus_property(self, value=None):
950
if value is None: # get
951
return dbus.String(self.host)
954
self.PropertyChanged(dbus.String(u"host"),
955
dbus.String(value, variant_level=1))
958
@dbus_service_property(_interface, signature=u"s", access=u"read")
959
def created_dbus_property(self):
960
return dbus.String(self._datetime_to_dbus(self.created))
962
# last_enabled - property
963
@dbus_service_property(_interface, signature=u"s", access=u"read")
964
def last_enabled_dbus_property(self):
965
if self.last_enabled is None:
966
return dbus.String(u"")
967
return dbus.String(self._datetime_to_dbus(self.last_enabled))
970
@dbus_service_property(_interface, signature=u"b",
972
def enabled_dbus_property(self, value=None):
973
if value is None: # get
974
return dbus.Boolean(self.enabled)
980
# last_checked_ok - property
981
@dbus_service_property(_interface, signature=u"s",
983
def last_checked_ok_dbus_property(self, value=None):
984
if value is not None:
987
if self.last_checked_ok is None:
988
return dbus.String(u"")
989
return dbus.String(self._datetime_to_dbus(self
993
@dbus_service_property(_interface, signature=u"t",
995
def timeout_dbus_property(self, value=None):
996
if value is None: # get
997
return dbus.UInt64(self.timeout_milliseconds())
998
self.timeout = datetime.timedelta(0, 0, 0, value)
1000
self.PropertyChanged(dbus.String(u"timeout"),
1001
dbus.UInt64(value, variant_level=1))
1002
if getattr(self, u"disable_initiator_tag", None) is None:
1004
# Reschedule timeout
1005
gobject.source_remove(self.disable_initiator_tag)
1006
self.disable_initiator_tag = None
1007
time_to_die = (self.
1008
_timedelta_to_milliseconds((self
1013
if time_to_die <= 0:
1014
# The timeout has passed
1017
self.disable_initiator_tag = (gobject.timeout_add
1018
(time_to_die, self.disable))
1020
# interval - property
1021
@dbus_service_property(_interface, signature=u"t",
1022
access=u"readwrite")
1023
def interval_dbus_property(self, value=None):
1024
if value is None: # get
1025
return dbus.UInt64(self.interval_milliseconds())
1026
self.interval = datetime.timedelta(0, 0, 0, value)
1028
self.PropertyChanged(dbus.String(u"interval"),
1029
dbus.UInt64(value, variant_level=1))
1030
if getattr(self, u"checker_initiator_tag", None) is None:
1032
# Reschedule checker run
1033
gobject.source_remove(self.checker_initiator_tag)
1034
self.checker_initiator_tag = (gobject.timeout_add
1035
(value, self.start_checker))
1036
self.start_checker() # Start one now, too
1038
# checker - property
1039
@dbus_service_property(_interface, signature=u"s",
1040
access=u"readwrite")
1041
def checker_dbus_property(self, value=None):
1042
if value is None: # get
1043
return dbus.String(self.checker_command)
1044
self.checker_command = value
1046
self.PropertyChanged(dbus.String(u"checker"),
1047
dbus.String(self.checker_command,
1050
# checker_running - property
1051
@dbus_service_property(_interface, signature=u"b",
1052
access=u"readwrite")
1053
def checker_running_dbus_property(self, value=None):
1054
if value is None: # get
1055
return dbus.Boolean(self.checker is not None)
1057
self.start_checker()
1061
# object_path - property
1062
@dbus_service_property(_interface, signature=u"o", access=u"read")
1063
def object_path_dbus_property(self):
1064
return self.dbus_object_path # is already a dbus.ObjectPath
1067
@dbus_service_property(_interface, signature=u"ay",
1068
access=u"write", byte_arrays=True)
1069
def secret_dbus_property(self, value):
1070
self.secret = str(value)
1075
class ProxyClient(object):
1076
def __init__(self, child_pipe, fpr, address):
1077
self._pipe = child_pipe
1078
self._pipe.send(('init', fpr, address))
1079
if not self._pipe.recv():
1082
def __getattribute__(self, name):
1083
if(name == '_pipe'):
1084
return super(ProxyClient, self).__getattribute__(name)
1085
self._pipe.send(('getattr', name))
1086
data = self._pipe.recv()
1087
if data[0] == 'data':
1089
if data[0] == 'function':
1090
def func(*args, **kwargs):
1091
self._pipe.send(('funcall', name, args, kwargs))
1092
return self._pipe.recv()[1]
1095
def __setattr__(self, name, value):
1096
if(name == '_pipe'):
1097
return super(ProxyClient, self).__setattr__(name, value)
1098
self._pipe.send(('setattr', name, value))
1101
750
class ClientHandler(socketserver.BaseRequestHandler, object):
1102
751
"""A class to handle client connections.
1105
754
Note: This will run in its own forked process."""
1107
756
def handle(self):
1108
with contextlib.closing(self.server.child_pipe) as child_pipe:
1109
logger.info(u"TCP connection from: %s",
1110
unicode(self.client_address))
1111
logger.debug(u"Pipe FD: %d",
1112
self.server.child_pipe.fileno())
757
logger.info(u"TCP connection from: %s",
758
unicode(self.client_address))
759
logger.debug(u"IPC Pipe FD: %d", self.server.pipe[1])
760
# Open IPC pipe to parent process
761
with closing(os.fdopen(self.server.pipe[1], u"w", 1)) as ipc:
1114
762
session = (gnutls.connection
1115
763
.ClientSession(self.request,
1116
764
gnutls.connection
1117
765
.X509Credentials()))
767
line = self.request.makefile().readline()
768
logger.debug(u"Protocol version: %r", line)
770
if int(line.strip().split()[0]) > 1:
772
except (ValueError, IndexError, RuntimeError), error:
773
logger.error(u"Unknown protocol version: %s", error)
1119
776
# Note: gnutls.connection.X509Credentials is really a
1120
777
# generic GnuTLS certificate credentials object so long as
1121
778
# no X.509 keys are added to it. Therefore, we can use it
1122
779
# here despite using OpenPGP certificates.
1124
781
#priority = u':'.join((u"NONE", u"+VERS-TLS1.1",
1125
782
# u"+AES-256-CBC", u"+SHA1",
1126
783
# u"+COMP-NULL", u"+CTYPE-OPENPGP",
1153
798
# established. Just abandon the request.
1155
800
logger.debug(u"Handshake succeeded")
1157
approval_required = False
1160
fpr = self.fingerprint(self.peer_certificate
1162
except (TypeError, gnutls.errors.GNUTLSError), error:
1163
logger.warning(u"Bad certificate: %s", error)
1165
logger.debug(u"Fingerprint: %s", fpr)
1168
client = ProxyClient(child_pipe, fpr,
1169
self.client_address)
1173
if client.approved_delay:
1174
delay = client.approved_delay
1175
client.approvals_pending += 1
1176
approval_required = True
1179
if not client.enabled:
1180
logger.warning(u"Client %s is disabled",
1182
if self.server.use_dbus:
1184
client.Rejected("Disabled")
1187
if client._approved or not client.approved_delay:
1188
#We are approved or approval is disabled
1190
elif client._approved is None:
1191
logger.info(u"Client %s need approval",
1193
if self.server.use_dbus:
1195
client.NeedApproval(
1196
client.approved_delay_milliseconds(),
1197
client.approved_by_default)
1199
logger.warning(u"Client %s was not approved",
1201
if self.server.use_dbus:
1203
client.Rejected("Disapproved")
1206
#wait until timeout or approved
1207
#x = float(client._timedelta_to_milliseconds(delay))
1208
time = datetime.datetime.now()
1209
client.changedstate.acquire()
1210
client.changedstate.wait(float(client._timedelta_to_milliseconds(delay) / 1000))
1211
client.changedstate.release()
1212
time2 = datetime.datetime.now()
1213
if (time2 - time) >= delay:
1214
if not client.approved_by_default:
1215
logger.warning("Client %s timed out while"
1216
" waiting for approval",
1218
if self.server.use_dbus:
1220
client.Rejected("Time out")
1225
delay -= time2 - time
1228
while sent_size < len(client.secret):
1229
# XXX handle session exception
1230
sent = session.send(client.secret[sent_size:])
1231
logger.debug(u"Sent: %d, remaining: %d",
1232
sent, len(client.secret)
1233
- (sent_size + sent))
1236
logger.info(u"Sending secret to %s", client.name)
1237
# bump the timeout as if seen
1239
if self.server.use_dbus:
802
fpr = self.fingerprint(self.peer_certificate(session))
803
except (TypeError, gnutls.errors.GNUTLSError), error:
804
logger.warning(u"Bad certificate: %s", error)
807
logger.debug(u"Fingerprint: %s", fpr)
1244
if approval_required:
1245
client.approvals_pending -= 1
809
for c in self.server.clients:
810
if c.fingerprint == fpr:
814
ipc.write(u"NOTFOUND %s %s\n"
815
% (fpr, unicode(self.client_address)))
818
# Have to check if client.still_valid(), since it is
819
# possible that the client timed out while establishing
820
# the GnuTLS session.
821
if not client.still_valid():
822
ipc.write(u"INVALID %s\n" % client.name)
825
ipc.write(u"SENDING %s\n" % client.name)
827
while sent_size < len(client.secret):
828
sent = session.send(client.secret[sent_size:])
829
logger.debug(u"Sent: %d, remaining: %d",
830
sent, len(client.secret)
831
- (sent_size + sent))
1249
836
def peer_certificate(session):
1312
class MultiprocessingMixIn(object):
1313
"""Like socketserver.ThreadingMixIn, but with multiprocessing"""
1314
def sub_process_main(self, request, address):
1316
self.finish_request(request, address)
1318
self.handle_error(request, address)
1319
self.close_request(request)
1321
def process_request(self, request, address):
1322
"""Start a new process to process the request."""
1323
multiprocessing.Process(target = self.sub_process_main,
1324
args = (request, address)).start()
1326
class MultiprocessingMixInWithPipe(MultiprocessingMixIn, object):
1327
""" adds a pipe to the MixIn """
899
class ForkingMixInWithPipe(socketserver.ForkingMixIn, object):
900
"""Like socketserver.ForkingMixIn, but also pass a pipe."""
1328
901
def process_request(self, request, client_address):
1329
902
"""Overrides and wraps the original process_request().
1331
904
This function creates a new pipe in self.pipe
1333
parent_pipe, self.child_pipe = multiprocessing.Pipe()
1335
super(MultiprocessingMixInWithPipe,
906
self.pipe = os.pipe()
907
super(ForkingMixInWithPipe,
1336
908
self).process_request(request, client_address)
1337
self.add_pipe(parent_pipe)
1338
def add_pipe(self, parent_pipe):
909
os.close(self.pipe[1]) # close write end
910
self.add_pipe(self.pipe[0])
911
def add_pipe(self, pipe):
1339
912
"""Dummy function; override as necessary"""
1342
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
916
class IPv6_TCPServer(ForkingMixInWithPipe,
1343
917
socketserver.TCPServer, object):
1344
918
"""IPv6-capable TCP server. Accepts 'None' as address and/or port
1456
1029
logger.debug(u"Handling IPC: FD = %d, condition = %s", source,
1457
1030
conditions_string)
1459
# Read a request from the child
1460
request = parent_pipe.recv()
1461
command = request[0]
1032
# Turn the pipe file descriptor into a Python file object
1033
if source not in file_objects:
1034
file_objects[source] = os.fdopen(source, u"r", 1)
1463
if command == 'init':
1465
address = request[2]
1467
for c in self.clients:
1468
if c.fingerprint == fpr:
1472
logger.warning(u"Client not found for fingerprint: %s, ad"
1473
u"dress: %s", fpr, address)
1476
mandos_dbus_service.ClientNotFound(fpr, address)
1477
parent_pipe.send(False)
1480
gobject.io_add_watch(parent_pipe.fileno(),
1481
gobject.IO_IN | gobject.IO_HUP,
1482
functools.partial(self.handle_ipc,
1483
parent_pipe = parent_pipe,
1484
client_object = client))
1485
parent_pipe.send(True)
1486
# remove the old hook in favor of the new above hook on same fileno
1036
# Read a line from the file object
1037
cmdline = file_objects[source].readline()
1038
if not cmdline: # Empty line means end of file
1039
# close the IPC pipe
1040
file_objects[source].close()
1041
del file_objects[source]
1043
# Stop calling this function
1488
if command == 'funcall':
1489
funcname = request[1]
1493
parent_pipe.send(('data', getattr(client_object, funcname)(*args, **kwargs)))
1495
if command == 'getattr':
1496
attrname = request[1]
1497
if callable(client_object.__getattribute__(attrname)):
1498
parent_pipe.send(('function',))
1500
parent_pipe.send(('data', client_object.__getattribute__(attrname)))
1502
if command == 'setattr':
1503
attrname = request[1]
1505
setattr(client_object, attrname, value)
1046
logger.debug(u"IPC command: %r", cmdline)
1048
# Parse and act on command
1049
cmd, args = cmdline.rstrip(u"\r\n").split(None, 1)
1051
if cmd == u"NOTFOUND":
1052
logger.warning(u"Client not found for fingerprint: %s",
1056
mandos_dbus_service.ClientNotFound(args)
1057
elif cmd == u"INVALID":
1058
for client in self.clients:
1059
if client.name == args:
1060
logger.warning(u"Client %s is invalid", args)
1066
logger.error(u"Unknown client %s is invalid", args)
1067
elif cmd == u"SENDING":
1068
for client in self.clients:
1069
if client.name == args:
1070
logger.info(u"Sending secret to %s", client.name)
1074
client.ReceivedSecret()
1077
logger.error(u"Sending secret to unknown client %s",
1080
logger.error(u"Unknown IPC command: %r", cmdline)
1082
# Keep calling this function