Make user defaults more secure on all systems.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@14341 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
CaS 2002-08-27 08:52:14 +00:00
parent 8b1fc0e981
commit 76266fba00
4 changed files with 67 additions and 43 deletions

View file

@ -1,3 +1,11 @@
2002-08-27 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSData.m: ([-writeToFile:atomically:]) Removed bogus line
which deleted files when it shouldn't.
* Source/NSUserDefaults.m: Use distributed lock to ensure that there
is no possible window when the defaults file is invalid ... not all
systems guarantee that the rename() system call is atomic.
2002-08-25 Richard Frith-Macdonald <rfm@gnu.org> 2002-08-25 Richard Frith-Macdonald <rfm@gnu.org>
* Source/WindowsFileHandle.m: Removed ... no longer used. * Source/WindowsFileHandle.m: Removed ... no longer used.

View file

@ -35,6 +35,7 @@
@class NSData; @class NSData;
@class NSTimer; @class NSTimer;
@class NSRecursiveLock; @class NSRecursiveLock;
@class NSDistributedLock;
/* Standard domains */ /* Standard domains */
GS_EXPORT NSString* const NSArgumentDomain; GS_EXPORT NSString* const NSArgumentDomain;
@ -125,6 +126,7 @@ GS_EXPORT NSString* const NSLocale;
NSDate *_lastSync; NSDate *_lastSync;
NSTimer *_tickingTimer; // for synchronization NSTimer *_tickingTimer; // for synchronization
NSRecursiveLock *_lock; NSRecursiveLock *_lock;
NSDistributedLock *_fileLock;
} }
/* Getting the Shared Instance */ /* Getting the Shared Instance */

View file

@ -857,7 +857,6 @@ failure:
att = [[mgr fileAttributesAtPath: path att = [[mgr fileAttributesAtPath: path
traverseLink: YES] mutableCopy]; traverseLink: YES] mutableCopy];
IF_NO_GC(TEST_AUTORELEASE(att)); IF_NO_GC(TEST_AUTORELEASE(att));
[mgr removeFileAtPath: path handler: nil];
} }
c = rename(thePath, theRealPath); c = rename(thePath, theRealPath);
@ -868,7 +867,7 @@ failure:
goto failure; goto failure;
} }
if (att) if (att != nil)
{ {
/* /*
* We have created a new file - so we attempt to make it's * We have created a new file - so we attempt to make it's

View file

@ -33,21 +33,23 @@
#include <errno.h> #include <errno.h>
#include <Foundation/NSUserDefaults.h> #include <Foundation/NSUserDefaults.h>
#include <Foundation/NSFileManager.h>
#include <Foundation/NSPathUtilities.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSDate.h>
#include <Foundation/NSUtilities.h>
#include <Foundation/NSArchiver.h> #include <Foundation/NSArchiver.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSBundle.h>
#include <Foundation/NSDate.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSDistributedLock.h>
#include <Foundation/NSException.h> #include <Foundation/NSException.h>
#include <Foundation/NSFileManager.h>
#include <Foundation/NSLock.h>
#include <Foundation/NSNotification.h> #include <Foundation/NSNotification.h>
#include <Foundation/NSTimer.h> #include <Foundation/NSPathUtilities.h>
#include <Foundation/NSProcessInfo.h> #include <Foundation/NSProcessInfo.h>
#include <Foundation/NSRunLoop.h> #include <Foundation/NSRunLoop.h>
#include <Foundation/NSBundle.h> #include <Foundation/NSThread.h>
#include <Foundation/NSTimer.h>
#include <Foundation/NSUtilities.h>
#include <Foundation/NSValue.h> #include <Foundation/NSValue.h>
#include <Foundation/NSLock.h>
#include <base/GSLocale.h> #include <base/GSLocale.h>
#include "GSPrivate.h" #include "GSPrivate.h"
@ -712,6 +714,9 @@ static NSString *pathForUser(NSString *user)
{ {
_defaultsDatabase = [pathForUser(NSUserName()) copy]; _defaultsDatabase = [pathForUser(NSUserName()) copy];
} }
_fileLock = [[NSDistributedLock alloc] initWithPath:
[_defaultsDatabase stringByAppendingPathExtension: @"lck"]];
_lock = [NSRecursiveLock new];
// Create an empty search list // Create an empty search list
_searchList = [[NSMutableArray alloc] initWithCapacity: 10]; _searchList = [[NSMutableArray alloc] initWithCapacity: 10];
@ -765,20 +770,22 @@ static NSString *pathForUser(NSString *user)
setObject: [NSMutableDictionaryClass dictionaryWithCapacity: 10] setObject: [NSMutableDictionaryClass dictionaryWithCapacity: 10]
forKey: NSRegistrationDomain]; forKey: NSRegistrationDomain];
_lock = [NSRecursiveLock new];
return self; return self;
} }
- (void) dealloc - (void) dealloc
{ {
if (_tickingTimer) if (_tickingTimer != nil)
[_tickingTimer invalidate]; {
[_tickingTimer invalidate];
}
RELEASE(_lastSync); RELEASE(_lastSync);
RELEASE(_searchList); RELEASE(_searchList);
RELEASE(_persDomains); RELEASE(_persDomains);
RELEASE(_tempDomains); RELEASE(_tempDomains);
RELEASE(_changedDomains); RELEASE(_changedDomains);
RELEASE(_dictionaryRep); RELEASE(_dictionaryRep);
RELEASE(_fileLock);
RELEASE(_lock); RELEASE(_lock);
[super dealloc]; [super dealloc];
} }
@ -1173,6 +1180,23 @@ static NSString *pathForUser(NSString *user)
[_lock lock]; [_lock lock];
while ([_fileLock tryLock] == NO)
{
CREATE_AUTORELEASE_POOL(arp);
NSDate *when;
when = [NSDate dateWithTimeIntervalSinceNow: 0.1];
if ([when timeIntervalSinceDate: [_fileLock lockDate]] > 5.0)
{
[_fileLock breakLock];
}
else
{
[NSThread sleepUntilDate: when];
}
RELEASE(arp);
}
if (_tickingTimer == nil) if (_tickingTimer == nil)
{ {
_tickingTimer = [NSTimer scheduledTimerWithTimeInterval: 30 _tickingTimer = [NSTimer scheduledTimerWithTimeInterval: 30
@ -1188,7 +1212,7 @@ static NSString *pathForUser(NSString *user)
*/ */
attr = [mgr fileAttributesAtPath: _defaultsDatabase attr = [mgr fileAttributesAtPath: _defaultsDatabase
traverseLink: YES]; traverseLink: YES];
if (_changedDomains == NO) if (_changedDomains == nil)
{ {
BOOL wantRead = NO; BOOL wantRead = NO;
@ -1215,6 +1239,7 @@ static NSString *pathForUser(NSString *user)
} }
if (wantRead == NO) if (wantRead == NO)
{ {
[_fileLock unlock];
[_lock unlock]; [_lock unlock];
return YES; return YES;
} }
@ -1239,6 +1264,7 @@ static NSString *pathForUser(NSString *user)
if (newDict == nil) if (newDict == nil)
{ {
NSLog(@"Unable to load defaults from '%@'", _defaultsDatabase); NSLog(@"Unable to load defaults from '%@'", _defaultsDatabase);
[_fileLock unlock];
[_lock unlock]; [_lock unlock];
return NO; return NO;
} }
@ -1269,25 +1295,23 @@ static NSString *pathForUser(NSString *user)
atPath: _defaultsDatabase]; atPath: _defaultsDatabase];
} }
if (_changedDomains) if (_changedDomains != nil)
{ // Synchronize both dictionaries { // Synchronize both dictionaries
NSEnumerator *enumerator = [_changedDomains objectEnumerator]; NSEnumerator *enumerator = [_changedDomains objectEnumerator];
IMP nextImp; NSString *domainName;
IMP pImp; NSDictionary *domain;
id obj, dict;
nextImp = [enumerator methodForSelector: nextObjectSel]; DESTROY(_changedDomains); // Retained by enumerator.
pImp = [_persDomains methodForSelector: objectForKeySel]; while ((domainName = [enumerator nextObject]) != nil)
while ((obj = (*nextImp)(enumerator, nextObjectSel)) != nil)
{ {
dict = (*pImp)(_persDomains, objectForKeySel, obj); domain = [_persDomains objectForKey: domainName];
if (dict) // Domain was added or changed if (domain != nil) // Domain was added or changed
{ {
[newDict setObject: dict forKey: obj]; [newDict setObject: domain forKey: domainName];
} }
else // Domain was removed else // Domain was removed
{ {
[newDict removeObjectForKey: obj]; [newDict removeObjectForKey: domainName];
} }
} }
RELEASE(_persDomains); RELEASE(_persDomains);
@ -1295,6 +1319,7 @@ static NSString *pathForUser(NSString *user)
// Save the changes // Save the changes
if (![_persDomains writeToFile: _defaultsDatabase atomically: YES]) if (![_persDomains writeToFile: _defaultsDatabase atomically: YES])
{ {
[_fileLock unlock];
[_lock unlock]; [_lock unlock];
return NO; return NO;
} }
@ -1318,6 +1343,7 @@ static NSString *pathForUser(NSString *user)
} }
} }
[_fileLock unlock];
[_lock unlock]; [_lock unlock];
return YES; return YES;
} }
@ -1575,32 +1601,21 @@ static NSString *pathForUser(NSString *user)
- (void) __changePersistentDomain: (NSString*)domainName - (void) __changePersistentDomain: (NSString*)domainName
{ {
NSEnumerator *enumerator = nil;
IMP nImp;
id obj;
[_lock lock]; [_lock lock];
DESTROY(_dictionaryRep); DESTROY(_dictionaryRep);
if (!_changedDomains) if (_changedDomains == nil)
{ {
_changedDomains = [[NSMutableArray alloc] initWithCapacity: 5]; _changedDomains = [[NSMutableArray alloc] initWithObjects: &domainName
count: 1];
updateCache(self); updateCache(self);
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
postNotificationName: NSUserDefaultsDidChangeNotification postNotificationName: NSUserDefaultsDidChangeNotification
object: self]; object: self];
} }
else if ([_changedDomains containsObject: domainName] == NO)
enumerator = [_changedDomains objectEnumerator];
nImp = [enumerator methodForSelector: nextObjectSel];
while ((obj = (*nImp)(enumerator, nextObjectSel)) != nil)
{ {
if ([obj isEqualToString: domainName]) [_changedDomains addObject: domainName];
{
[_lock unlock];
return;
}
} }
[_changedDomains addObject: domainName];
[_lock unlock]; [_lock unlock];
return; return;
} }