* We now store passwords for network servers securely instead of storing them in plain text in the Growl preferences. Heh.
authorevands
Mon Jul 28 21:53:02 2008 +0000 (2008-07-28)
changeset 4153899d3019a60a
parent 4152 099dfa400709
child 4154 a2dbe798edf8
* We now store passwords for network servers securely instead of storing them in plain text in the Growl preferences. Heh.
* Remove unneeded code related to resolving Bonjour clients immediately, since we want to resolve them as-needed rather than storing a static IP/port.
Core/Source/GrowlBrowserEntry.h
Core/Source/GrowlBrowserEntry.m
Core/Source/GrowlPreferencePane.h
Core/Source/GrowlPreferencePane.m
     1.1 --- a/Core/Source/GrowlBrowserEntry.h	Mon Jul 28 15:23:14 2008 +0000
     1.2 +++ b/Core/Source/GrowlBrowserEntry.h	Mon Jul 28 21:53:02 2008 +0000
     1.3 @@ -12,10 +12,12 @@
     1.4  
     1.5  @interface GrowlBrowserEntry : NSObject {
     1.6  	CFMutableDictionaryRef properties;
     1.7 +	NSString			   *password;
     1.8 +	BOOL				   didPasswordLookup;
     1.9  	GrowlPreferencePane    *owner;
    1.10  }
    1.11  - (id) initWithDictionary:(NSDictionary *)dict;
    1.12 -- (id) initWithComputerName:(NSString *)name netService:(NSNetService *)service;
    1.13 +- (id) initWithComputerName:(NSString *)name;
    1.14  
    1.15  - (BOOL) use;
    1.16  - (void) setUse:(BOOL)flag;
    1.17 @@ -26,15 +28,11 @@
    1.18  - (NSString *) computerName;
    1.19  - (void) setComputerName:(NSString *)name;
    1.20  
    1.21 -- (NSNetService *) netService;
    1.22 -- (void) setNetService:(NSNetService *)service;
    1.23 -
    1.24  - (NSString *) password;
    1.25  - (void) setPassword:(NSString *)password;
    1.26  
    1.27  - (NSDictionary *) properties;
    1.28  
    1.29 -- (void) setAddress:(NSData *)address;
    1.30  - (void) setOwner:(GrowlPreferencePane *)pref;
    1.31  
    1.32  @end
     2.1 --- a/Core/Source/GrowlBrowserEntry.m	Mon Jul 28 15:23:14 2008 +0000
     2.2 +++ b/Core/Source/GrowlBrowserEntry.m	Mon Jul 28 21:53:02 2008 +0000
     2.3 @@ -10,6 +10,10 @@
     2.4  #import "GrowlPreferencePane.h"
     2.5  #include "CFDictionaryAdditions.h"
     2.6  #include "CFMutableDictionaryAdditions.h"
     2.7 +#include <Security/SecKeychain.h>
     2.8 +#include <Security/SecKeychainItem.h>
     2.9 +
    2.10 +#define GrowlBrowserEntryKeychainServiceName "GrowlOutgoingNetworkConnection"
    2.11  
    2.12  @implementation GrowlBrowserEntry
    2.13  
    2.14 @@ -21,11 +25,10 @@
    2.15  	return self;
    2.16  }
    2.17  
    2.18 -- (id) initWithComputerName:(NSString *)name netService:(NSNetService *)service {
    2.19 +- (id) initWithComputerName:(NSString *)name {
    2.20  	if ((self = [self init])) {
    2.21  		properties = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    2.22  		CFDictionarySetValue(properties, CFSTR("computer"), name);
    2.23 -		CFDictionarySetValue(properties, CFSTR("netservice"), service);
    2.24  		CFDictionarySetValue(properties, CFSTR("use"), kCFBooleanFalse);
    2.25  		CFDictionarySetValue(properties, CFSTR("active"), kCFBooleanTrue);
    2.26  	}
    2.27 @@ -60,29 +63,76 @@
    2.28  	[owner writeForwardDestinations];
    2.29  }
    2.30  
    2.31 -- (NSNetService *) netService {
    2.32 -	return (NSNetService *)CFDictionaryGetValue(properties, CFSTR("netservice"));
    2.33 +- (NSString *) password {
    2.34 +	if (!didPasswordLookup) {
    2.35 +		unsigned char *passwordChars;
    2.36 +		UInt32 passwordLength;
    2.37 +		OSStatus status;
    2.38 +		const char *computerNameChars = [[self computerName] UTF8String];
    2.39 +		status = SecKeychainFindGenericPassword(NULL,
    2.40 +												strlen(GrowlBrowserEntryKeychainServiceName), GrowlBrowserEntryKeychainServiceName,
    2.41 +												strlen(computerNameChars), computerNameChars,
    2.42 +												&passwordLength, (void **)&passwordChars, NULL);		
    2.43 +		if (status == noErr) {
    2.44 +			password = [[NSString alloc] initWithBytes:passwordChars
    2.45 +												length:passwordLength
    2.46 +											  encoding:NSUTF8StringEncoding];
    2.47 +			SecKeychainItemFreeContent(NULL, password);
    2.48 +		} else {
    2.49 +			if (status != errSecItemNotFound)
    2.50 +				NSLog(@"Failed to retrieve password for %@ from keychain. Error: %d", status);
    2.51 +			password = nil;
    2.52 +		}
    2.53 +		
    2.54 +		didPasswordLookup = YES;
    2.55 +	}
    2.56 +
    2.57 +	
    2.58 +	return password;
    2.59  }
    2.60  
    2.61 -- (void) setNetService:(NSNetService *)service {
    2.62 -	CFDictionarySetValue(properties, CFSTR("netservice"), service);
    2.63 -}
    2.64 +- (void) setPassword:(NSString *)inPassword {
    2.65 +	if (password != inPassword) {
    2.66 +		[password release];
    2.67 +		password = [inPassword copy];
    2.68 +	}
    2.69  
    2.70 -- (NSString *) password {
    2.71 -	return (NSString *)CFDictionaryGetValue(properties, CFSTR("password"));
    2.72 -}
    2.73 -
    2.74 -- (void) setPassword:(NSString *)password {
    2.75 -	if (password)
    2.76 -		CFDictionarySetValue(properties, CFSTR("password"), password);
    2.77 -	else
    2.78 -		CFDictionaryRemoveValue(properties, CFSTR("password"));
    2.79 -	[owner writeForwardDestinations];
    2.80 -}
    2.81 -
    2.82 -- (void) setAddress:(NSData *)address {
    2.83 -	CFDictionarySetValue(properties, CFSTR("address"), address);
    2.84 -	CFDictionaryRemoveValue(properties, CFSTR("netservice"));
    2.85 +	// Store the password to the keychain
    2.86 +	// XXX TODO Use AIKeychain
    2.87 +	const char *passwordChars = password ? [password UTF8String] : "";
    2.88 +	OSStatus status;
    2.89 +	SecKeychainItemRef itemRef = nil;
    2.90 +	const char *computerNameChars = [[self computerName] UTF8String];
    2.91 +	status = SecKeychainFindGenericPassword(NULL,
    2.92 +											strlen(GrowlBrowserEntryKeychainServiceName), GrowlBrowserEntryKeychainServiceName,
    2.93 +											strlen(computerNameChars), computerNameChars,
    2.94 +											NULL, NULL, &itemRef);
    2.95 +	if (status == errSecItemNotFound) {
    2.96 +		// add new item
    2.97 +		status = SecKeychainAddGenericPassword(NULL,
    2.98 +											   strlen(GrowlBrowserEntryKeychainServiceName), GrowlBrowserEntryKeychainServiceName,
    2.99 +											   strlen(computerNameChars), computerNameChars,
   2.100 +											   strlen(passwordChars), passwordChars, NULL);
   2.101 +		if (status)
   2.102 +			NSLog(@"Failed to add password to keychain.");
   2.103 +	} else {
   2.104 +		// change existing password
   2.105 +		SecKeychainAttribute attrs[] = {
   2.106 +			{ kSecAccountItemAttr, strlen(computerNameChars), (char *)computerNameChars },
   2.107 +			{ kSecServiceItemAttr, strlen(GrowlBrowserEntryKeychainServiceName), (char *)GrowlBrowserEntryKeychainServiceName }
   2.108 +		};
   2.109 +		const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
   2.110 +		status = SecKeychainItemModifyAttributesAndData(itemRef,		// the item reference
   2.111 +														&attributes,	// no change to attributes
   2.112 +														strlen(passwordChars),			// length of password
   2.113 +														passwordChars		// pointer to password data
   2.114 +														);
   2.115 +		if (itemRef)
   2.116 +			CFRelease(itemRef);
   2.117 +		if (status)
   2.118 +			NSLog(@"Failed to change password in keychain.");
   2.119 +	}
   2.120 +	
   2.121  	[owner writeForwardDestinations];
   2.122  }
   2.123  
   2.124 @@ -95,6 +145,8 @@
   2.125  }
   2.126  
   2.127  - (void) dealloc {
   2.128 +	[password release];
   2.129 +
   2.130  	CFRelease(properties);
   2.131  	[super dealloc];
   2.132  }
     3.1 --- a/Core/Source/GrowlPreferencePane.h	Mon Jul 28 15:23:14 2008 +0000
     3.2 +++ b/Core/Source/GrowlPreferencePane.h	Mon Jul 28 21:53:02 2008 +0000
     3.3 @@ -80,7 +80,6 @@
     3.4  	//"Network" tab pane
     3.5  	NSMutableArray					*services;
     3.6  	NSNetServiceBrowser				*browser;
     3.7 -	NSNetService					*serviceBeingResolved;
     3.8  	int								currentServiceIndex;
     3.9  	IBOutlet NSArrayController		*servicesArrayController;
    3.10  	IBOutlet NSTableColumn			*servicePasswordColumn;
     4.1 --- a/Core/Source/GrowlPreferencePane.m	Mon Jul 28 15:23:14 2008 +0000
     4.2 +++ b/Core/Source/GrowlPreferencePane.m	Mon Jul 28 21:53:02 2008 +0000
     4.3 @@ -478,8 +478,7 @@
     4.4  	NSEnumerator *enumerator = [services objectEnumerator];
     4.5  	GrowlBrowserEntry *entry;
     4.6  	while ((entry = [enumerator nextObject]))
     4.7 -		if (![entry netService])
     4.8 -			[destinations addObject:[entry properties]];
     4.9 +		[destinations addObject:[entry properties]];
    4.10  	[preferencesController setObject:destinations forKey:GrowlForwardDestinationsKey];
    4.11  	[destinations release];
    4.12  }
    4.13 @@ -949,7 +948,7 @@
    4.14  		return;
    4.15  
    4.16  	// add a new entry at the end
    4.17 -	entry = [[GrowlBrowserEntry alloc] initWithComputerName:name netService:aNetService];
    4.18 +	entry = [[GrowlBrowserEntry alloc] initWithComputerName:name];
    4.19  	[self willChangeValueForKey:@"services"];
    4.20  	[services addObject:entry];
    4.21  	[self didChangeValueForKey:@"services"];
    4.22 @@ -972,52 +971,14 @@
    4.23  		}
    4.24  	}
    4.25  
    4.26 -	if (serviceBeingResolved && [serviceBeingResolved isEqual:aNetService]) {
    4.27 -		[serviceBeingResolved stop];
    4.28 -		[serviceBeingResolved release];
    4.29 -		serviceBeingResolved = nil;
    4.30 -	}
    4.31 -
    4.32  	if (!moreComing)
    4.33  		[self writeForwardDestinations];
    4.34  }
    4.35  
    4.36 -- (void) netServiceDidResolveAddress:(NSNetService *)sender {
    4.37 -	NSArray *addresses = [sender addresses];
    4.38 -	if ([addresses count] > 0U) {
    4.39 -		NSData *address = [addresses objectAtIndex:0U];
    4.40 -		GrowlBrowserEntry *entry = [services objectAtIndex:currentServiceIndex];
    4.41 -		[entry setAddress:address];
    4.42 -		[self writeForwardDestinations];
    4.43 -	}
    4.44 -}
    4.45 -
    4.46  #pragma mark Bonjour
    4.47  
    4.48  - (void) resolveService:(id)sender {
    4.49 -	int row = [sender selectedRow];
    4.50 -	if (row != -1) {
    4.51 -		GrowlBrowserEntry *entry = [services objectAtIndex:row];
    4.52 -		NSNetService *serviceToResolve = [entry netService];
    4.53 -		if (serviceToResolve) {
    4.54 -			// Make sure to cancel any previous resolves.
    4.55 -			if (serviceBeingResolved) {
    4.56 -				[serviceBeingResolved stop];
    4.57 -				[serviceBeingResolved release];
    4.58 -				serviceBeingResolved = nil;
    4.59 -			}
    4.60 -
    4.61 -			currentServiceIndex = row;
    4.62 -			serviceBeingResolved = serviceToResolve;
    4.63 -			[serviceBeingResolved retain];
    4.64 -			[serviceBeingResolved setDelegate:self];
    4.65 -			if ([serviceBeingResolved respondsToSelector:@selector(resolveWithTimeout:)])
    4.66 -				[serviceBeingResolved resolveWithTimeout:5.0];
    4.67 -			else
    4.68 -				// this selector is deprecated in 10.4
    4.69 -				[serviceBeingResolved resolve];
    4.70 -		}
    4.71 -	}
    4.72 +	NSLog(@"What calls resolveService:?");
    4.73  }
    4.74  
    4.75  - (NSMutableArray *) services {