1.1 --- a/Core/Source/GrowlBrowserEntry.m Wed May 09 02:33:04 2007 +0000
1.2 +++ b/Core/Source/GrowlBrowserEntry.m Mon Jul 28 21:53:02 2008 +0000
1.3 @@ -10,6 +10,10 @@
1.4 #import "GrowlPreferencePane.h"
1.5 #include "CFDictionaryAdditions.h"
1.6 #include "CFMutableDictionaryAdditions.h"
1.7 +#include <Security/SecKeychain.h>
1.8 +#include <Security/SecKeychainItem.h>
1.9 +
1.10 +#define GrowlBrowserEntryKeychainServiceName "GrowlOutgoingNetworkConnection"
1.11
1.12 @implementation GrowlBrowserEntry
1.13
1.14 @@ -21,11 +25,10 @@
1.15 return self;
1.16 }
1.17
1.18 -- (id) initWithComputerName:(NSString *)name netService:(NSNetService *)service {
1.19 +- (id) initWithComputerName:(NSString *)name {
1.20 if ((self = [self init])) {
1.21 properties = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1.22 CFDictionarySetValue(properties, CFSTR("computer"), name);
1.23 - CFDictionarySetValue(properties, CFSTR("netservice"), service);
1.24 CFDictionarySetValue(properties, CFSTR("use"), kCFBooleanFalse);
1.25 CFDictionarySetValue(properties, CFSTR("active"), kCFBooleanTrue);
1.26 }
1.27 @@ -60,29 +63,76 @@
1.28 [owner writeForwardDestinations];
1.29 }
1.30
1.31 -- (NSNetService *) netService {
1.32 - return (NSNetService *)CFDictionaryGetValue(properties, CFSTR("netservice"));
1.33 +- (NSString *) password {
1.34 + if (!didPasswordLookup) {
1.35 + unsigned char *passwordChars;
1.36 + UInt32 passwordLength;
1.37 + OSStatus status;
1.38 + const char *computerNameChars = [[self computerName] UTF8String];
1.39 + status = SecKeychainFindGenericPassword(NULL,
1.40 + strlen(GrowlBrowserEntryKeychainServiceName), GrowlBrowserEntryKeychainServiceName,
1.41 + strlen(computerNameChars), computerNameChars,
1.42 + &passwordLength, (void **)&passwordChars, NULL);
1.43 + if (status == noErr) {
1.44 + password = [[NSString alloc] initWithBytes:passwordChars
1.45 + length:passwordLength
1.46 + encoding:NSUTF8StringEncoding];
1.47 + SecKeychainItemFreeContent(NULL, password);
1.48 + } else {
1.49 + if (status != errSecItemNotFound)
1.50 + NSLog(@"Failed to retrieve password for %@ from keychain. Error: %d", status);
1.51 + password = nil;
1.52 + }
1.53 +
1.54 + didPasswordLookup = YES;
1.55 + }
1.56 +
1.57 +
1.58 + return password;
1.59 }
1.60
1.61 -- (void) setNetService:(NSNetService *)service {
1.62 - CFDictionarySetValue(properties, CFSTR("netservice"), service);
1.63 -}
1.64 +- (void) setPassword:(NSString *)inPassword {
1.65 + if (password != inPassword) {
1.66 + [password release];
1.67 + password = [inPassword copy];
1.68 + }
1.69
1.70 -- (NSString *) password {
1.71 - return (NSString *)CFDictionaryGetValue(properties, CFSTR("password"));
1.72 -}
1.73 -
1.74 -- (void) setPassword:(NSString *)password {
1.75 - if (password)
1.76 - CFDictionarySetValue(properties, CFSTR("password"), password);
1.77 - else
1.78 - CFDictionaryRemoveValue(properties, CFSTR("password"));
1.79 - [owner writeForwardDestinations];
1.80 -}
1.81 -
1.82 -- (void) setAddress:(NSData *)address {
1.83 - CFDictionarySetValue(properties, CFSTR("address"), address);
1.84 - CFDictionaryRemoveValue(properties, CFSTR("netservice"));
1.85 + // Store the password to the keychain
1.86 + // XXX TODO Use AIKeychain
1.87 + const char *passwordChars = password ? [password UTF8String] : "";
1.88 + OSStatus status;
1.89 + SecKeychainItemRef itemRef = nil;
1.90 + const char *computerNameChars = [[self computerName] UTF8String];
1.91 + status = SecKeychainFindGenericPassword(NULL,
1.92 + strlen(GrowlBrowserEntryKeychainServiceName), GrowlBrowserEntryKeychainServiceName,
1.93 + strlen(computerNameChars), computerNameChars,
1.94 + NULL, NULL, &itemRef);
1.95 + if (status == errSecItemNotFound) {
1.96 + // add new item
1.97 + status = SecKeychainAddGenericPassword(NULL,
1.98 + strlen(GrowlBrowserEntryKeychainServiceName), GrowlBrowserEntryKeychainServiceName,
1.99 + strlen(computerNameChars), computerNameChars,
1.100 + strlen(passwordChars), passwordChars, NULL);
1.101 + if (status)
1.102 + NSLog(@"Failed to add password to keychain.");
1.103 + } else {
1.104 + // change existing password
1.105 + SecKeychainAttribute attrs[] = {
1.106 + { kSecAccountItemAttr, strlen(computerNameChars), (char *)computerNameChars },
1.107 + { kSecServiceItemAttr, strlen(GrowlBrowserEntryKeychainServiceName), (char *)GrowlBrowserEntryKeychainServiceName }
1.108 + };
1.109 + const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
1.110 + status = SecKeychainItemModifyAttributesAndData(itemRef, // the item reference
1.111 + &attributes, // no change to attributes
1.112 + strlen(passwordChars), // length of password
1.113 + passwordChars // pointer to password data
1.114 + );
1.115 + if (itemRef)
1.116 + CFRelease(itemRef);
1.117 + if (status)
1.118 + NSLog(@"Failed to change password in keychain.");
1.119 + }
1.120 +
1.121 [owner writeForwardDestinations];
1.122 }
1.123
1.124 @@ -95,6 +145,8 @@
1.125 }
1.126
1.127 - (void) dealloc {
1.128 + [password release];
1.129 +
1.130 CFRelease(properties);
1.131 [super dealloc];
1.132 }