128
128
logger.setLevel(level)
131
class PGPError(Exception):
132
"""Exception if encryption/decryption fails"""
131
class CryptoError(Exception):
136
class PGPEngine(object):
135
class Crypto(object):
137
136
"""A simple class for OpenPGP symmetric encryption & decryption"""
138
137
def __init__(self):
139
138
self.gnupg = GnuPGInterface.GnuPG()
388
387
"""A representation of a client host served by this server.
391
approved: bool(); 'None' if not yet approved/disapproved
390
_approved: bool(); 'None' if not yet approved/disapproved
392
391
approval_delay: datetime.timedelta(); Time to wait for approval
393
392
approval_duration: datetime.timedelta(); Duration of one approval
394
393
checker: subprocess.Popen(); a running checker process used
436
435
def timeout_milliseconds(self):
437
436
"Return the 'timeout' attribute in milliseconds"
438
return timedelta_to_milliseconds(self.timeout)
437
return _timedelta_to_milliseconds(self.timeout)
440
439
def extended_timeout_milliseconds(self):
441
440
"Return the 'extended_timeout' attribute in milliseconds"
442
return timedelta_to_milliseconds(self.extended_timeout)
441
return _timedelta_to_milliseconds(self.extended_timeout)
444
443
def interval_milliseconds(self):
445
444
"Return the 'interval' attribute in milliseconds"
446
return timedelta_to_milliseconds(self.interval)
445
return _timedelta_to_milliseconds(self.interval)
448
447
def approval_delay_milliseconds(self):
449
return timedelta_to_milliseconds(self.approval_delay)
448
return _timedelta_to_milliseconds(self.approval_delay)
451
450
def __init__(self, name = None, config=None):
452
451
"""Note: the 'checker' key in 'config' sets the
496
495
self.checker_callback_tag = None
497
496
self.checker_command = config["checker"]
498
497
self.current_checker_command = None
498
self._approved = None
500
499
self.approved_by_default = config.get("approved_by_default",
502
501
self.approvals_pending = 0
576
575
self.checker_callback_tag = None
577
576
self.checker = None
578
577
if os.WIFEXITED(condition):
579
self.last_checker_status = os.WEXITSTATUS(condition)
578
self.last_checker_status = os.WEXITSTATUS(condition)
580
579
if self.last_checker_status == 0:
581
580
logger.info("Checker for %(name)s succeeded",
602
601
gobject.source_remove(self.disable_initiator_tag)
603
602
if getattr(self, "enabled", False):
604
603
self.disable_initiator_tag = (gobject.timeout_add
605
(timedelta_to_milliseconds
604
(_timedelta_to_milliseconds
606
605
(timeout), self.disable))
607
606
self.expires = datetime.datetime.utcnow() + timeout
1069
1068
datetime_to_dbus, "LastApprovalRequest")
1070
1069
approved_by_default = notifychangeproperty(dbus.Boolean,
1071
1070
"ApprovedByDefault")
1072
approval_delay = notifychangeproperty(dbus.UInt64,
1071
approval_delay = notifychangeproperty(dbus.UInt16,
1073
1072
"ApprovalDelay",
1075
timedelta_to_milliseconds)
1074
_timedelta_to_milliseconds)
1076
1075
approval_duration = notifychangeproperty(
1077
dbus.UInt64, "ApprovalDuration",
1078
type_func = timedelta_to_milliseconds)
1076
dbus.UInt16, "ApprovalDuration",
1077
type_func = _timedelta_to_milliseconds)
1079
1078
host = notifychangeproperty(dbus.String, "Host")
1080
timeout = notifychangeproperty(dbus.UInt64, "Timeout",
1079
timeout = notifychangeproperty(dbus.UInt16, "Timeout",
1082
timedelta_to_milliseconds)
1081
_timedelta_to_milliseconds)
1083
1082
extended_timeout = notifychangeproperty(
1084
dbus.UInt64, "ExtendedTimeout",
1085
type_func = timedelta_to_milliseconds)
1086
interval = notifychangeproperty(dbus.UInt64,
1083
dbus.UInt16, "ExtendedTimeout",
1084
type_func = _timedelta_to_milliseconds)
1085
interval = notifychangeproperty(dbus.UInt16,
1089
timedelta_to_milliseconds)
1088
_timedelta_to_milliseconds)
1090
1089
checker_command = notifychangeproperty(dbus.String, "Checker")
1092
1091
del notifychangeproperty
1136
1135
def _reset_approved(self):
1137
self.approved = None
1136
self._approved = None
1140
1139
def approve(self, value=True):
1141
1140
self.send_changedstate()
1142
self.approved = value
1143
gobject.timeout_add(timedelta_to_milliseconds
1141
self._approved = value
1142
gobject.timeout_add(_timedelta_to_milliseconds
1144
1143
(self.approval_duration),
1145
1144
self._reset_approved)
1260
1259
access="readwrite")
1261
1260
def ApprovalDuration_dbus_property(self, value=None):
1262
1261
if value is None: # get
1263
return dbus.UInt64(timedelta_to_milliseconds(
1262
return dbus.UInt64(_timedelta_to_milliseconds(
1264
1263
self.approval_duration))
1265
1264
self.approval_duration = datetime.timedelta(0, 0, 0, value)
1280
1279
def Host_dbus_property(self, value=None):
1281
1280
if value is None: # get
1282
1281
return dbus.String(self.host)
1283
self.host = unicode(value)
1285
1284
# Created - property
1286
1285
@dbus_service_property(_interface, signature="s", access="read")
1380
1379
def Checker_dbus_property(self, value=None):
1381
1380
if value is None: # get
1382
1381
return dbus.String(self.checker_command)
1383
self.checker_command = unicode(value)
1382
self.checker_command = value
1385
1384
# CheckerRunning - property
1386
1385
@dbus_service_property(_interface, signature="b",
1415
1414
raise KeyError()
1417
1416
def __getattribute__(self, name):
1417
if(name == '_pipe'):
1419
1418
return super(ProxyClient, self).__getattribute__(name)
1420
1419
self._pipe.send(('getattr', name))
1421
1420
data = self._pipe.recv()
1430
1429
def __setattr__(self, name, value):
1430
if(name == '_pipe'):
1432
1431
return super(ProxyClient, self).__setattr__(name, value)
1433
1432
self._pipe.send(('setattr', name, value))
1503
1502
logger.warning("Bad certificate: %s", error)
1505
1504
logger.debug("Fingerprint: %s", fpr)
1505
if self.server.use_dbus:
1507
client.NewRequest(str(self.client_address))
1508
1510
client = ProxyClient(child_pipe, fpr,
1528
1526
client.Rejected("Disabled")
1531
if client.approved or not client.approval_delay:
1529
if client._approved or not client.approval_delay:
1532
1530
#We are approved or approval is disabled
1534
elif client.approved is None:
1532
elif client._approved is None:
1535
1533
logger.info("Client %s needs approval",
1537
1535
if self.server.use_dbus:
1551
1549
time = datetime.datetime.now()
1552
1550
client.changedstate.acquire()
1553
1551
(client.changedstate.wait
1554
(float(client.timedelta_to_milliseconds(delay)
1552
(float(client._timedelta_to_milliseconds(delay)
1556
1554
client.changedstate.release()
1557
1555
time2 = datetime.datetime.now()
2244
2242
# enabled if its last checker was sucessful. Clients
2245
2243
# whose checker failed before we stored its state is
2246
2244
# assumed to have failed all checkers during downtime.
2247
if client["enabled"]:
2248
if client["expires"] <= (datetime.datetime
2250
# Client has expired
2245
if client["enabled"] and client["last_checked_ok"]:
2246
if ((datetime.datetime.utcnow()
2247
- client["last_checked_ok"])
2248
> client["interval"]):
2251
2249
if client["last_checker_status"] != 0:
2252
2250
client["enabled"] = False
2287
2285
tcp_server.clients[client_name].secret = (
2288
pgp.decrypt(tcp_server.clients[client_name]
2290
client_settings[client_name]
2286
crypt.decrypt(tcp_server.clients[client_name]
2288
client_settings[client_name]
2293
2291
# If decryption fails, we use secret from new settings
2294
logger.debug("Failed to decrypt {0} old secret"
2295
.format(client_name))
2296
2292
tcp_server.clients[client_name].secret = (
2297
2293
client_settings[client_name]["secret"])
2398
2394
# based on what config file has. If config file is
2399
2395
# removed/edited, old secret will thus be unrecovable.
2401
with PGPEngine() as pgp:
2397
with Crypto() as crypt:
2402
2398
for client in tcp_server.clients.itervalues():
2403
2399
key = client_settings[client.name]["secret"]
2404
client.encrypted_secret = pgp.encrypt(client.secret,
2400
client.encrypted_secret = crypt.encrypt(client.secret,
2406
2402
client_dict = {}
2408
2404
# A list of attributes that will not be stored when