88useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the normal network, you won't be able to send or sometimes receive messages.
99
1010
11- import threading
12- import sys
13- from addresses import *
14- import highlevelcrypto
15- import Queue
16- import pickle
17- import os
18- import time
11+ # Libraries.
1912import ConfigParser
20- import socket
13+ import os
14+ import pickle
15+ import Queue
2116import random
17+ import socket
18+ import sys
19+ import stat
20+ import threading
21+ import time
22+
23+ # Project imports.
24+ from addresses import *
2225import highlevelcrypto
2326import shared
2427import helper_startup
2528
2629
30+
2731config = ConfigParser .SafeConfigParser ()
2832myECCryptorObjects = {}
2933MyECSubscriptionCryptorObjects = {}
@@ -143,6 +147,7 @@ def lookupAppdataFolder():
143147 else :
144148 print stringToLog
145149 except IOError :
150+ # Old directory may not exist.
146151 pass
147152 dataFolder = dataFolder + '/'
148153 return dataFolder
@@ -188,23 +193,26 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address):
188193 return False
189194
190195def safeConfigGetBoolean (section ,field ):
191- try :
192- return config .getboolean (section ,field )
193- except :
194- return False
196+ try :
197+ return config .getboolean (section ,field )
198+ except :
199+ return False
195200
196201def decodeWalletImportFormat (WIFstring ):
197202 fullString = arithmetic .changebase (WIFstring ,58 ,256 )
198203 privkey = fullString [:- 4 ]
199204 if fullString [- 4 :] != hashlib .sha256 (hashlib .sha256 (privkey ).digest ()).digest ()[:4 ]:
200- sys .stderr .write ('Major problem! When trying to decode one of your private keys, the checksum failed. Here is the PRIVATE key: %s\n ' % str (WIFstring ))
205+ logger .error ('Major problem! When trying to decode one of your private keys, the checksum '
206+ 'failed. Here is the PRIVATE key: %s\n ' % str (WIFstring ))
201207 return ""
202208 else :
203209 #checksum passed
204210 if privkey [0 ] == '\x80 ' :
205211 return privkey [1 :]
206212 else :
207- sys .stderr .write ('Major problem! When trying to decode one of your private keys, the checksum passed but the key doesn\' t begin with hex 80. Here is the PRIVATE key: %s\n ' % str (WIFstring ))
213+ logger .error ('Major problem! When trying to decode one of your private keys, the '
214+ 'checksum passed but the key doesn\' t begin with hex 80. Here is the '
215+ 'PRIVATE key: %s\n ' % str (WIFstring ))
208216 return ""
209217
210218
@@ -213,19 +221,32 @@ def reloadMyAddressHashes():
213221 myECCryptorObjects .clear ()
214222 myAddressesByHash .clear ()
215223 #myPrivateKeys.clear()
224+
225+ keyfileSecure = checkSensitiveFilePermissions (appdata + 'keys.dat' )
216226 configSections = config .sections ()
227+ hasEnabledKeys = False
217228 for addressInKeysFile in configSections :
218229 if addressInKeysFile <> 'bitmessagesettings' :
219230 isEnabled = config .getboolean (addressInKeysFile , 'enabled' )
220231 if isEnabled :
232+ hasEnabledKeys = True
221233 status ,addressVersionNumber ,streamNumber ,hash = decodeAddress (addressInKeysFile )
222234 if addressVersionNumber == 2 or addressVersionNumber == 3 :
223- privEncryptionKey = decodeWalletImportFormat (config .get (addressInKeysFile , 'privencryptionkey' )).encode ('hex' ) #returns a simple 32 bytes of information encoded in 64 Hex characters, or null if there was an error
235+ # Returns a simple 32 bytes of information encoded in 64 Hex characters,
236+ # or null if there was an error.
237+ privEncryptionKey = decodeWalletImportFormat (
238+ config .get (addressInKeysFile , 'privencryptionkey' )).encode ('hex' )
239+
224240 if len (privEncryptionKey ) == 64 :#It is 32 bytes encoded as 64 hex characters
225241 myECCryptorObjects [hash ] = highlevelcrypto .makeCryptor (privEncryptionKey )
226242 myAddressesByHash [hash ] = addressInKeysFile
243+
227244 else :
228- sys .stderr .write ('Error in reloadMyAddressHashes: Can\' t handle address versions other than 2 or 3.\n ' )
245+ logger .error ('Error in reloadMyAddressHashes: Can\' t handle address '
246+ 'versions other than 2 or 3.\n ' )
247+
248+ if not keyfileSecure :
249+ fixSensitiveFilePermissions (appdata + 'keys.dat' , hasEnabledKeys )
229250
230251def reloadBroadcastSendersForWhichImWatching ():
231252 logger .debug ('reloading subscriptions...' )
@@ -276,6 +297,7 @@ def doCleanShutdown():
276297 sqlSubmitQueue .put ('exit' )
277298 sqlLock .release ()
278299 logger .info ('Finished flushing inventory.' )
300+
279301 # Wait long enough to guarantee that any running proof of work worker threads will check the
280302 # shutdown variable and exit. If the main thread closes before they do then they won't stop.
281303 time .sleep (.25 )
@@ -313,5 +335,40 @@ def fixPotentiallyInvalidUTF8Data(text):
313335 output = 'Part of the message is corrupt. The message cannot be displayed the normal way.\n \n ' + repr (text )
314336 return output
315337
338+ # Checks sensitive file permissions for inappropriate umask during keys.dat creation.
339+ # (Or unwise subsequent chmod.)
340+ #
341+ # Returns true iff file appears to have appropriate permissions.
342+ def checkSensitiveFilePermissions (filename ):
343+ if sys .platform == 'win32' :
344+ # TODO: This might deserve extra checks by someone familiar with
345+ # Windows systems.
346+ return True
347+ else :
348+ present_permissions = os .stat (filename )[0 ]
349+ disallowed_permissions = stat .S_IRWXG | stat .S_IRWXO
350+ return present_permissions & disallowed_permissions == 0
351+
352+ # Fixes permissions on a sensitive file.
353+ def fixSensitiveFilePermissions (filename , hasEnabledKeys ):
354+ if hasEnabledKeys :
355+ logger .warning ('Keyfile had insecure permissions, and there were enabled keys. '
356+ 'The truly paranoid should stop using them immediately.' )
357+ else :
358+ logger .warning ('Keyfile had insecure permissions, but there were no enabled keys.' )
359+ try :
360+ present_permissions = os .stat (filename )[0 ]
361+ disallowed_permissions = stat .S_IRWXG | stat .S_IRWXO
362+ allowed_permissions = ((1 << 32 )- 1 ) ^ disallowed_permissions
363+ new_permissions = (
364+ allowed_permissions & present_permissions )
365+ os .chmod (filename , new_permissions )
366+
367+ logger .info ('Keyfile permissions automatically fixed.' )
368+
369+ except Exception , e :
370+ logger .exception ('Keyfile permissions could not be fixed.' )
371+ raise
372+
316373helper_startup .loadConfig ()
317374from debug import logger
0 commit comments