245
240
last_checked_ok: datetime.datetime(); (UTC) or None
246
241
timeout: datetime.timedelta(); How long from last_checked_ok
247
until this client is disabled
242
until this client is invalid
248
243
interval: datetime.timedelta(); How often to start a new checker
249
244
disable_hook: If set, called by disable() as disable_hook(self)
250
245
checker: subprocess.Popen(); a running checker process used
251
246
to see if the client lives.
252
247
'None' if no process is running.
253
248
checker_initiator_tag: a gobject event source tag, or None
254
disable_initiator_tag: - '' -
249
disable_initiator_tag: - '' -
255
250
checker_callback_tag: - '' -
256
251
checker_command: string; External command which is run to check if
257
252
client lives. %() expansions are done at
258
253
runtime with vars(self) as dict, so that for
259
254
instance %(name)s can be used in the command.
260
255
current_checker_command: string; current running checker_command
261
approved_delay: datetime.timedelta(); Time to wait for approval
262
_approved: bool(); 'None' if not yet approved/disapproved
263
approved_duration: datetime.timedelta(); Duration of one approval
267
def _timedelta_to_milliseconds(td):
268
"Convert a datetime.timedelta() to milliseconds"
269
return ((td.days * 24 * 60 * 60 * 1000)
270
+ (td.seconds * 1000)
271
+ (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))
273
265
def timeout_milliseconds(self):
274
266
"Return the 'timeout' attribute in milliseconds"
275
return self._timedelta_to_milliseconds(self.timeout)
267
return self._datetime_to_milliseconds(self.timeout)
277
269
def interval_milliseconds(self):
278
270
"Return the 'interval' attribute in milliseconds"
279
return self._timedelta_to_milliseconds(self.interval)
281
def approved_delay_milliseconds(self):
282
return self._timedelta_to_milliseconds(self.approved_delay)
271
return self._datetime_to_milliseconds(self.interval)
284
273
def __init__(self, name = None, disable_hook=None, config=None):
285
274
"""Note: the 'checker' key in 'config' sets the
321
309
self.checker_command = config[u"checker"]
322
310
self.current_checker_command = None
323
311
self.last_connect = None
324
self.approvals_pending = 0
325
self._approved = None
326
self.approved_by_default = config.get(u"approved_by_default",
328
self.approved_delay = string_to_delta(
329
config[u"approved_delay"])
330
self.approved_duration = string_to_delta(
331
config[u"approved_duration"])
332
self.changedstate = multiprocessing_manager.Condition(multiprocessing_manager.Lock())
334
def send_changedstate(self):
335
self.changedstate.acquire()
336
self.changedstate.notify_all()
337
self.changedstate.release()
339
313
def enable(self):
340
314
"""Start this client's checker and timeout hooks"""
341
315
if getattr(self, u"enabled", False):
342
316
# Already enabled
344
self.send_changedstate()
345
318
self.last_enabled = datetime.datetime.utcnow()
346
319
# Schedule a new checker to be started an 'interval' from now,
347
320
# and every interval from then on.
348
321
self.checker_initiator_tag = (gobject.timeout_add
349
322
(self.interval_milliseconds(),
350
323
self.start_checker))
324
# Also start a new checker *right now*.
351
326
# Schedule a disable() when 'timeout' has passed
352
327
self.disable_initiator_tag = (gobject.timeout_add
353
328
(self.timeout_milliseconds(),
355
330
self.enabled = True
356
# Also start a new checker *right now*.
359
def disable(self, quiet=True):
360
333
"""Disable this client."""
361
334
if not getattr(self, "enabled", False):
364
self.send_changedstate()
366
logger.info(u"Disabling client %s", self.name)
336
logger.info(u"Disabling client %s", self.name)
367
337
if getattr(self, u"disable_initiator_tag", False):
368
338
gobject.source_remove(self.disable_initiator_tag)
369
339
self.disable_initiator_tag = None
493
458
logger.debug(u"Stopping checker for %(name)s", vars(self))
495
460
os.kill(self.checker.pid, signal.SIGTERM)
497
462
#if self.checker.poll() is None:
498
463
# os.kill(self.checker.pid, signal.SIGKILL)
499
464
except OSError, error:
500
465
if error.errno != errno.ESRCH: # No such process
502
467
self.checker = None
504
def dbus_service_property(dbus_interface, signature=u"v",
505
access=u"readwrite", byte_arrays=False):
506
"""Decorators for marking methods of a DBusObjectWithProperties to
507
become properties on the D-Bus.
509
The decorated method will be called with no arguments by "Get"
510
and with one argument by "Set".
512
The parameters, where they are supported, are the same as
513
dbus.service.method, except there is only "signature", since the
514
type from Get() and the type sent to Set() is the same.
516
# Encoding deeply encoded byte arrays is not supported yet by the
517
# "Set" method, so we fail early here:
518
if byte_arrays and signature != u"ay":
519
raise ValueError(u"Byte arrays not supported for non-'ay'"
520
u" signature %r" % signature)
522
func._dbus_is_property = True
523
func._dbus_interface = dbus_interface
524
func._dbus_signature = signature
525
func._dbus_access = access
526
func._dbus_name = func.__name__
527
if func._dbus_name.endswith(u"_dbus_property"):
528
func._dbus_name = func._dbus_name[:-14]
529
func._dbus_get_args_options = {u'byte_arrays': byte_arrays }
534
class DBusPropertyException(dbus.exceptions.DBusException):
535
"""A base class for D-Bus property-related exceptions
537
def __unicode__(self):
538
return unicode(str(self))
541
class DBusPropertyAccessException(DBusPropertyException):
542
"""A property's access permissions disallows an operation.
547
class DBusPropertyNotFound(DBusPropertyException):
548
"""An attempt was made to access a non-existing property.
553
class DBusObjectWithProperties(dbus.service.Object):
554
"""A D-Bus object with properties.
556
Classes inheriting from this can use the dbus_service_property
557
decorator to expose methods as D-Bus properties. It exposes the
558
standard Get(), Set(), and GetAll() methods on the D-Bus.
562
def _is_dbus_property(obj):
563
return getattr(obj, u"_dbus_is_property", False)
565
def _get_all_dbus_properties(self):
566
"""Returns a generator of (name, attribute) pairs
568
return ((prop._dbus_name, prop)
570
inspect.getmembers(self, self._is_dbus_property))
572
def _get_dbus_property(self, interface_name, property_name):
573
"""Returns a bound method if one exists which is a D-Bus
574
property with the specified name and interface.
576
for name in (property_name,
577
property_name + u"_dbus_property"):
578
prop = getattr(self, name, None)
580
or not self._is_dbus_property(prop)
581
or prop._dbus_name != property_name
582
or (interface_name and prop._dbus_interface
583
and interface_name != prop._dbus_interface)):
587
raise DBusPropertyNotFound(self.dbus_object_path + u":"
588
+ interface_name + u"."
591
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ss",
593
def Get(self, interface_name, property_name):
594
"""Standard D-Bus property Get() method, see D-Bus standard.
596
prop = self._get_dbus_property(interface_name, property_name)
597
if prop._dbus_access == u"write":
598
raise DBusPropertyAccessException(property_name)
600
if not hasattr(value, u"variant_level"):
602
return type(value)(value, variant_level=value.variant_level+1)
604
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ssv")
605
def Set(self, interface_name, property_name, value):
606
"""Standard D-Bus property Set() method, see D-Bus standard.
608
prop = self._get_dbus_property(interface_name, property_name)
609
if prop._dbus_access == u"read":
610
raise DBusPropertyAccessException(property_name)
611
if prop._dbus_get_args_options[u"byte_arrays"]:
612
# The byte_arrays option is not supported yet on
613
# signatures other than "ay".
614
if prop._dbus_signature != u"ay":
616
value = dbus.ByteArray(''.join(unichr(byte)
620
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"s",
621
out_signature=u"a{sv}")
622
def GetAll(self, interface_name):
623
"""Standard D-Bus property GetAll() method, see D-Bus
626
Note: Will not include properties with access="write".
629
for name, prop in self._get_all_dbus_properties():
631
and interface_name != prop._dbus_interface):
632
# Interface non-empty but did not match
634
# Ignore write-only properties
635
if prop._dbus_access == u"write":
638
if not hasattr(value, u"variant_level"):
641
all[name] = type(value)(value, variant_level=
642
value.variant_level+1)
643
return dbus.Dictionary(all, signature=u"sv")
645
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
647
path_keyword='object_path',
648
connection_keyword='connection')
649
def Introspect(self, object_path, connection):
650
"""Standard D-Bus method, overloaded to insert property tags.
652
xmlstring = dbus.service.Object.Introspect(self, object_path,
655
document = xml.dom.minidom.parseString(xmlstring)
656
def make_tag(document, name, prop):
657
e = document.createElement(u"property")
658
e.setAttribute(u"name", name)
659
e.setAttribute(u"type", prop._dbus_signature)
660
e.setAttribute(u"access", prop._dbus_access)
662
for if_tag in document.getElementsByTagName(u"interface"):
663
for tag in (make_tag(document, name, prop)
665
in self._get_all_dbus_properties()
666
if prop._dbus_interface
667
== if_tag.getAttribute(u"name")):
668
if_tag.appendChild(tag)
669
# Add the names to the return values for the
670
# "org.freedesktop.DBus.Properties" methods
671
if (if_tag.getAttribute(u"name")
672
== u"org.freedesktop.DBus.Properties"):
673
for cn in if_tag.getElementsByTagName(u"method"):
674
if cn.getAttribute(u"name") == u"Get":
675
for arg in cn.getElementsByTagName(u"arg"):
676
if (arg.getAttribute(u"direction")
678
arg.setAttribute(u"name", u"value")
679
elif cn.getAttribute(u"name") == u"GetAll":
680
for arg in cn.getElementsByTagName(u"arg"):
681
if (arg.getAttribute(u"direction")
683
arg.setAttribute(u"name", u"props")
684
xmlstring = document.toxml(u"utf-8")
686
except (AttributeError, xml.dom.DOMException,
687
xml.parsers.expat.ExpatError), error:
688
logger.error(u"Failed to override Introspection method",
693
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):
694
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()
836
662
# PropertyChanged - signal
837
663
@dbus.service.signal(_interface, signature=u"sv")
838
664
def PropertyChanged(self, property, value):
668
# ReceivedSecret - signal
843
669
@dbus.service.signal(_interface)
670
def ReceivedSecret(self):
848
674
# Rejected - signal
849
@dbus.service.signal(_interface, signature=u"s")
850
def Rejected(self, reason):
854
# NeedApproval - signal
855
@dbus.service.signal(_interface, signature=u"db")
856
def NeedApproval(self, timeout, default):
863
@dbus.service.method(_interface, in_signature=u"b")
864
def Approve(self, value):
868
@dbus.service.method(_interface)
870
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(),
872
724
# Enable - method
873
725
@dbus.service.method(_interface)
892
744
def StopChecker(self):
893
745
self.stop_checker()
897
# approved_pending - property
898
@dbus_service_property(_interface, signature=u"b", access=u"read")
899
def approved_pending_dbus_property(self):
900
return dbus.Boolean(self.approved_pending())
902
# approved_by_default - property
903
@dbus_service_property(_interface, signature=u"b",
905
def approved_by_default_dbus_property(self):
906
return dbus.Boolean(self.approved_by_default)
908
# approved_delay - property
909
@dbus_service_property(_interface, signature=u"t",
911
def approved_delay_dbus_property(self):
912
return dbus.UInt64(self.approved_delay_milliseconds())
914
# approved_duration - property
915
@dbus_service_property(_interface, signature=u"t",
917
def approved_duration_dbus_property(self):
918
return dbus.UInt64(self._timedelta_to_milliseconds(
919
self.approved_duration))
922
@dbus_service_property(_interface, signature=u"s", access=u"read")
923
def name_dbus_property(self):
924
return dbus.String(self.name)
926
# fingerprint - property
927
@dbus_service_property(_interface, signature=u"s", access=u"read")
928
def fingerprint_dbus_property(self):
929
return dbus.String(self.fingerprint)
932
@dbus_service_property(_interface, signature=u"s",
934
def host_dbus_property(self, value=None):
935
if value is None: # get
936
return dbus.String(self.host)
939
self.PropertyChanged(dbus.String(u"host"),
940
dbus.String(value, variant_level=1))
943
@dbus_service_property(_interface, signature=u"s", access=u"read")
944
def created_dbus_property(self):
945
return dbus.String(self._datetime_to_dbus(self.created))
947
# last_enabled - property
948
@dbus_service_property(_interface, signature=u"s", access=u"read")
949
def last_enabled_dbus_property(self):
950
if self.last_enabled is None:
951
return dbus.String(u"")
952
return dbus.String(self._datetime_to_dbus(self.last_enabled))
955
@dbus_service_property(_interface, signature=u"b",
957
def enabled_dbus_property(self, value=None):
958
if value is None: # get
959
return dbus.Boolean(self.enabled)
965
# last_checked_ok - property
966
@dbus_service_property(_interface, signature=u"s",
968
def last_checked_ok_dbus_property(self, value=None):
969
if value is not None:
972
if self.last_checked_ok is None:
973
return dbus.String(u"")
974
return dbus.String(self._datetime_to_dbus(self
978
@dbus_service_property(_interface, signature=u"t",
980
def timeout_dbus_property(self, value=None):
981
if value is None: # get
982
return dbus.UInt64(self.timeout_milliseconds())
983
self.timeout = datetime.timedelta(0, 0, 0, value)
985
self.PropertyChanged(dbus.String(u"timeout"),
986
dbus.UInt64(value, variant_level=1))
987
if getattr(self, u"disable_initiator_tag", None) is None:
990
gobject.source_remove(self.disable_initiator_tag)
991
self.disable_initiator_tag = None
993
_timedelta_to_milliseconds((self
999
# The timeout has passed
1002
self.disable_initiator_tag = (gobject.timeout_add
1003
(time_to_die, self.disable))
1005
# interval - property
1006
@dbus_service_property(_interface, signature=u"t",
1007
access=u"readwrite")
1008
def interval_dbus_property(self, value=None):
1009
if value is None: # get
1010
return dbus.UInt64(self.interval_milliseconds())
1011
self.interval = datetime.timedelta(0, 0, 0, value)
1013
self.PropertyChanged(dbus.String(u"interval"),
1014
dbus.UInt64(value, variant_level=1))
1015
if getattr(self, u"checker_initiator_tag", None) is None:
1017
# Reschedule checker run
1018
gobject.source_remove(self.checker_initiator_tag)
1019
self.checker_initiator_tag = (gobject.timeout_add
1020
(value, self.start_checker))
1021
self.start_checker() # Start one now, too
1023
# checker - property
1024
@dbus_service_property(_interface, signature=u"s",
1025
access=u"readwrite")
1026
def checker_dbus_property(self, value=None):
1027
if value is None: # get
1028
return dbus.String(self.checker_command)
1029
self.checker_command = value
1031
self.PropertyChanged(dbus.String(u"checker"),
1032
dbus.String(self.checker_command,
1035
# checker_running - property
1036
@dbus_service_property(_interface, signature=u"b",
1037
access=u"readwrite")
1038
def checker_running_dbus_property(self, value=None):
1039
if value is None: # get
1040
return dbus.Boolean(self.checker is not None)
1042
self.start_checker()
1046
# object_path - property
1047
@dbus_service_property(_interface, signature=u"o", access=u"read")
1048
def object_path_dbus_property(self):
1049
return self.dbus_object_path # is already a dbus.ObjectPath
1052
@dbus_service_property(_interface, signature=u"ay",
1053
access=u"write", byte_arrays=True)
1054
def secret_dbus_property(self, value):
1055
self.secret = str(value)
1060
class ProxyClient(object):
1061
def __init__(self, child_pipe, fpr, address):
1062
self._pipe = child_pipe
1063
self._pipe.send(('init', fpr, address))
1064
if not self._pipe.recv():
1067
def __getattribute__(self, name):
1068
if(name == '_pipe'):
1069
return super(ProxyClient, self).__getattribute__(name)
1070
self._pipe.send(('getattr', name))
1071
data = self._pipe.recv()
1072
if data[0] == 'data':
1074
if data[0] == 'function':
1075
def func(*args, **kwargs):
1076
self._pipe.send(('funcall', name, args, kwargs))
1077
return self._pipe.recv()[1]
1080
def __setattr__(self, name, value):
1081
if(name == '_pipe'):
1082
return super(ProxyClient, self).__setattr__(name, value)
1083
self._pipe.send(('setattr', name, value))
1086
750
class ClientHandler(socketserver.BaseRequestHandler, object):
1087
751
"""A class to handle client connections.
1090
754
Note: This will run in its own forked process."""
1092
756
def handle(self):
1093
with contextlib.closing(self.server.child_pipe) as child_pipe:
1094
logger.info(u"TCP connection from: %s",
1095
unicode(self.client_address))
1096
logger.debug(u"Pipe FD: %d",
1097
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:
1099
762
session = (gnutls.connection
1100
763
.ClientSession(self.request,
1101
764
gnutls.connection
1102
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)
1104
776
# Note: gnutls.connection.X509Credentials is really a
1105
777
# generic GnuTLS certificate credentials object so long as
1106
778
# no X.509 keys are added to it. Therefore, we can use it
1107
779
# here despite using OpenPGP certificates.
1109
781
#priority = u':'.join((u"NONE", u"+VERS-TLS1.1",
1110
782
# u"+AES-256-CBC", u"+SHA1",
1111
783
# u"+COMP-NULL", u"+CTYPE-OPENPGP",
1138
798
# established. Just abandon the request.
1140
800
logger.debug(u"Handshake succeeded")
1142
approval_required = False
1145
fpr = self.fingerprint(self.peer_certificate
1147
except (TypeError, gnutls.errors.GNUTLSError), error:
1148
logger.warning(u"Bad certificate: %s", error)
1150
logger.debug(u"Fingerprint: %s", fpr)
1153
client = ProxyClient(child_pipe, fpr,
1154
self.client_address)
1158
if client.approved_delay:
1159
delay = client.approved_delay
1160
client.approvals_pending += 1
1161
approval_required = True
1164
if not client.enabled:
1165
logger.warning(u"Client %s is disabled",
1167
if self.server.use_dbus:
1169
client.Rejected("Disabled")
1172
if client._approved or not client.approved_delay:
1173
#We are approved or approval is disabled
1175
elif client._approved is None:
1176
logger.info(u"Client %s need approval",
1178
if self.server.use_dbus:
1180
client.NeedApproval(
1181
client.approved_delay_milliseconds(),
1182
client.approved_by_default)
1184
logger.warning(u"Client %s was not approved",
1186
if self.server.use_dbus:
1188
client.Rejected("Disapproved")
1191
#wait until timeout or approved
1192
#x = float(client._timedelta_to_milliseconds(delay))
1193
time = datetime.datetime.now()
1194
client.changedstate.acquire()
1195
client.changedstate.wait(float(client._timedelta_to_milliseconds(delay) / 1000))
1196
client.changedstate.release()
1197
time2 = datetime.datetime.now()
1198
if (time2 - time) >= delay:
1199
if not client.approved_by_default:
1200
logger.warning("Client %s timed out while"
1201
" waiting for approval",
1203
if self.server.use_dbus:
1205
client.Rejected("Time out")
1210
delay -= time2 - time
1213
while sent_size < len(client.secret):
1214
# XXX handle session exception
1215
sent = session.send(client.secret[sent_size:])
1216
logger.debug(u"Sent: %d, remaining: %d",
1217
sent, len(client.secret)
1218
- (sent_size + sent))
1221
logger.info(u"Sending secret to %s", client.name)
1222
# bump the timeout as if seen
1224
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)
1229
if approval_required:
1230
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))
1234
836
def peer_certificate(session):
1297
class MultiprocessingMixIn(object):
1298
"""Like socketserver.ThreadingMixIn, but with multiprocessing"""
1299
def sub_process_main(self, request, address):
1301
self.finish_request(request, address)
1303
self.handle_error(request, address)
1304
self.close_request(request)
1306
def process_request(self, request, address):
1307
"""Start a new process to process the request."""
1308
multiprocessing.Process(target = self.sub_process_main,
1309
args = (request, address)).start()
1311
class MultiprocessingMixInWithPipe(MultiprocessingMixIn, object):
1312
""" adds a pipe to the MixIn """
899
class ForkingMixInWithPipe(socketserver.ForkingMixIn, object):
900
"""Like socketserver.ForkingMixIn, but also pass a pipe."""
1313
901
def process_request(self, request, client_address):
1314
902
"""Overrides and wraps the original process_request().
1316
904
This function creates a new pipe in self.pipe
1318
parent_pipe, self.child_pipe = multiprocessing.Pipe()
1320
super(MultiprocessingMixInWithPipe,
906
self.pipe = os.pipe()
907
super(ForkingMixInWithPipe,
1321
908
self).process_request(request, client_address)
1322
self.child_pipe.close()
1323
self.add_pipe(parent_pipe)
1325
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):
1326
912
"""Dummy function; override as necessary"""
1329
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
916
class IPv6_TCPServer(ForkingMixInWithPipe,
1330
917
socketserver.TCPServer, object):
1331
918
"""IPv6-capable TCP server. Accepts 'None' as address and/or port
1442
1028
if cond & condition)
1443
1029
logger.debug(u"Handling IPC: FD = %d, condition = %s", source,
1444
1030
conditions_string)
1446
# error or the other end of multiprocessing.Pipe has closed
1447
if condition & gobject.IO_HUP or condition & gobject.IO_ERR:
1450
# Read a request from the child
1451
request = parent_pipe.recv()
1452
logger.debug(u"IPC request: %s", repr(request))
1453
command = request[0]
1455
if command == 'init':
1457
address = request[2]
1459
for c in self.clients:
1460
if c.fingerprint == fpr:
1464
logger.warning(u"Client not found for fingerprint: %s, ad"
1465
u"dress: %s", fpr, address)
1468
mandos_dbus_service.ClientNotFound(fpr, address)
1469
parent_pipe.send(False)
1472
gobject.io_add_watch(parent_pipe.fileno(),
1473
gobject.IO_IN | gobject.IO_HUP,
1474
functools.partial(self.handle_ipc,
1475
parent_pipe = parent_pipe,
1476
client_object = client))
1477
parent_pipe.send(True)
1478
# remove the old hook in favor of the new above hook on same fileno
1480
if command == 'funcall':
1481
funcname = request[1]
1485
parent_pipe.send(('data', getattr(client_object, funcname)(*args, **kwargs)))
1487
if command == 'getattr':
1488
attrname = request[1]
1489
if callable(client_object.__getattribute__(attrname)):
1490
parent_pipe.send(('function',))
1492
parent_pipe.send(('data', client_object.__getattribute__(attrname)))
1494
if command == 'setattr':
1495
attrname = request[1]
1497
setattr(client_object, attrname, value)
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)
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
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