331
331
interval: datetime.timedelta(); How often to start a new checker
332
332
last_approval_request: datetime.datetime(); (UTC) or None
333
333
last_checked_ok: datetime.datetime(); (UTC) or None
334
last_checker_status: integer between 0 and 255 reflecting exit status
335
of last checker. -1 reflect crashed checker,
335
last_checker_status: integer between 0 and 255 reflecting exit
336
status of last checker. -1 reflects crashed
337
338
last_enabled: datetime.datetime(); (UTC)
338
339
name: string; from the config file, used in log messages and
339
340
D-Bus identifiers
419
420
self.changedstate = (multiprocessing_manager
420
421
.Condition(multiprocessing_manager
422
self.client_structure = [attr for attr in self.__dict__.iterkeys() if not attr.startswith("_")]
423
self.client_structure = [attr for attr in
424
self.__dict__.iterkeys()
425
if not attr.startswith("_")]
423
426
self.client_structure.append("client_structure")
425
428
for name, t in inspect.getmembers(type(self),
426
lambda obj: isinstance(obj, property)):
427
432
if not name.startswith("_"):
428
433
self.client_structure.append(name)
611
616
self.checker = None
613
# Encrypts a client secret and stores it in a varible encrypted_secret
618
# Encrypts a client secret and stores it in a varible
614
620
def encrypt_secret(self, key):
615
# Encryption-key need to be of a specific size, so we hash inputed key
621
# Encryption-key need to be of a specific size, so we hash
616
623
hasheng = hashlib.sha256()
617
624
hasheng.update(key)
618
625
encryptionkey = hasheng.digest()
620
# Create validation hash so we know at decryption if it was sucessful
627
# Create validation hash so we know at decryption if it was
621
629
hasheng = hashlib.sha256()
622
630
hasheng.update(self.secret)
623
631
validationhash = hasheng.digest()
626
634
iv = os.urandom(Crypto.Cipher.AES.block_size)
627
635
ciphereng = Crypto.Cipher.AES.new(encryptionkey,
628
Crypto.Cipher.AES.MODE_CFB, iv)
636
Crypto.Cipher.AES.MODE_CFB,
629
638
ciphertext = ciphereng.encrypt(validationhash+self.secret)
630
639
self.encrypted_secret = (ciphertext, iv)
639
648
# Decrypt encrypted secret
640
649
ciphertext, iv = self.encrypted_secret
641
650
ciphereng = Crypto.Cipher.AES.new(encryptionkey,
642
Crypto.Cipher.AES.MODE_CFB, iv)
651
Crypto.Cipher.AES.MODE_CFB,
643
653
plain = ciphereng.decrypt(ciphertext)
645
655
# Validate decrypted secret to know if it was succesful
648
658
secret = plain[hasheng.digest_size:]
649
659
hasheng.update(secret)
651
# if validation fails, we use key as new secret. Otherwhise, we use
652
# the decrypted secret
661
# if validation fails, we use key as new secret. Otherwhise,
662
# we use the decrypted secret
653
663
if hasheng.digest() == validationhash:
654
664
self.secret = secret
1932
1942
parser.add_argument("--no-ipv6", action="store_false",
1933
1943
dest="use_ipv6", help="Do not use IPv6")
1934
1944
parser.add_argument("--no-restore", action="store_false",
1935
dest="restore", help="Do not restore stored state",
1945
dest="restore", help="Do not restore stored"
1946
" state", default=True)
1938
1948
options = parser.parse_args()
2137
2147
# with exceptions for any special settings as defined above
2138
2148
client_settings = dict((clientname,
2140
(value if setting not in special_settings
2141
else special_settings[setting](clientname)))
2142
for setting, value in client_config.items(clientname)))
2151
if setting not in special_settings
2152
else special_settings[setting]
2154
for setting, value in
2155
client_config.items(clientname)))
2143
2156
for clientname in client_config.sections())
2145
2158
old_client_settings = {}
2146
2159
clients_data = []
2148
# Get client data and settings from last running state.
2161
# Get client data and settings from last running state.
2149
2162
if server_settings["restore"]:
2151
2164
with open(stored_state_path, "rb") as stored_state:
2152
clients_data, old_client_settings = pickle.load(stored_state)
2165
clients_data, old_client_settings = (pickle.load
2153
2167
os.remove(stored_state_path)
2154
2168
except IOError as e:
2155
logger.warning("Could not load persistant state: {0}".format(e))
2169
logger.warning("Could not load persistant state: {0}"
2156
2171
if e.errno != errno.ENOENT:
2169
2184
# For each value in new config, check if it differs
2170
2185
# from the old config value (Except for the "secret"
2172
if name != "secret" and value != old_client_settings[client_name][name]:
2187
if (name != "secret" and
2188
value != old_client_settings[client_name][name]):
2173
2189
setattr(client, name, value)
2174
2190
except KeyError:
2177
# Clients who has passed its expire date, can still be enabled if its
2178
# last checker was sucessful. Clients who checkers failed before we
2179
# stored it state is asumed to had failed checker during downtime.
2193
# Clients who has passed its expire date, can still be enabled
2194
# if its last checker was sucessful. Clients who checkers
2195
# failed before we stored it state is asumed to had failed
2196
# checker during downtime.
2180
2197
if client["enabled"] and client["last_checked_ok"]:
2181
if ((datetime.datetime.utcnow() - client["last_checked_ok"])
2182
> client["interval"]):
2198
if ((datetime.datetime.utcnow()
2199
- client["last_checked_ok"]) > client["interval"]):
2183
2200
if client["last_checker_status"] != 0:
2184
2201
client["enabled"] = False
2186
client["expires"] = datetime.datetime.utcnow() + client["timeout"]
2203
client["expires"] = (datetime.datetime.utcnow()
2204
+ client["timeout"])
2188
2206
client["changedstate"] = (multiprocessing_manager
2189
2207
.Condition(multiprocessing_manager
2192
new_client = ClientDBusTransitional.__new__(ClientDBusTransitional)
2210
new_client = (ClientDBusTransitional.__new__
2211
(ClientDBusTransitional))
2193
2212
tcp_server.clients[client_name] = new_client
2194
2213
new_client.bus = bus
2195
2214
for name, value in client.iteritems():
2198
2217
{ord("."): ord("_"),
2199
2218
ord("-"): ord("_")})
2200
2219
new_client.dbus_object_path = (dbus.ObjectPath
2201
("/clients/" + client_object_name))
2221
+ client_object_name))
2202
2222
DBusObjectWithProperties.__init__(new_client,
2203
2223
new_client.bus,
2204
new_client.dbus_object_path)
2206
2227
tcp_server.clients[client_name] = Client.__new__(Client)
2207
2228
for name, value in client.iteritems():
2208
2229
setattr(tcp_server.clients[client_name], name, value)
2210
2231
tcp_server.clients[client_name].decrypt_secret(
2211
client_settings[client_name]["secret"])
2232
client_settings[client_name]["secret"])
2213
2234
# Create/remove clients based on new changes made to config
2214
2235
for clientname in set(old_client_settings) - set(client_settings):
2215
2236
del tcp_server.clients[clientname]
2216
2237
for clientname in set(client_settings) - set(old_client_settings):
2217
tcp_server.clients[clientname] = (client_class(name = clientname,
2238
tcp_server.clients[clientname] = (client_class(name
2219
2241
client_settings
2223
2244
if not tcp_server.clients:
2224
2245
logger.warning("No clients defined")
2308
2329
if not (tcp_server.clients or client_settings):
2311
# Store client before exiting. Secrets are encrypted with key based
2312
# on what config file has. If config file is removed/edited, old
2313
# secret will thus be unrecovable.
2332
# Store client before exiting. Secrets are encrypted with key
2333
# based on what config file has. If config file is
2334
# removed/edited, old secret will thus be unrecovable.
2315
2336
for client in tcp_server.clients.itervalues():
2316
client.encrypt_secret(client_settings[client.name]["secret"])
2337
client.encrypt_secret(client_settings[client.name]
2318
2340
client_dict = {}
2320
# A list of attributes that will not be stored when shuting down.
2321
exclude = set(("bus", "changedstate", "secret"))
2342
# A list of attributes that will not be stored when
2344
exclude = set(("bus", "changedstate", "secret"))
2322
2345
for name, typ in inspect.getmembers(dbus.service.Object):
2323
2346
exclude.add(name)
2327
2350
if attr not in exclude:
2328
2351
client_dict[attr] = getattr(client, attr)
2330
clients.append(client_dict)
2353
clients.append(client_dict)
2331
2354
del client_settings[client.name]["secret"]
2334
with os.fdopen(os.open(stored_state_path, os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0600), "wb") as stored_state:
2357
with os.fdopen(os.open(stored_state_path,
2358
os.O_CREAT|os.O_WRONLY|os.O_TRUNC,
2359
0600), "wb") as stored_state:
2335
2360
pickle.dump((clients, client_settings), stored_state)
2336
2361
except IOError as e:
2337
logger.warning("Could not save persistant state: {0}".format(e))
2362
logger.warning("Could not save persistant state: {0}"
2338
2364
if e.errno != errno.ENOENT: