Revision: 21837
http://sourceforge.net/p/bibdesk/svn/21837
Author: hofman
Date: 2018-02-07 19:31:02 +0000 (Wed, 07 Feb 2018)
Log Message:
-----------
Change keychain item format for sharing client, use service name as account and
generic service name. Update old format items to new format automatically.
Modified Paths:
--------------
trunk/bibdesk/BDSKPasswordController.h
trunk/bibdesk/BDSKPasswordController.m
trunk/bibdesk/BDSKSharingClient.m
trunk/bibdesk/BDSKSharingServer.m
trunk/bibdesk/BibPref_Sharing.m
Modified: trunk/bibdesk/BDSKPasswordController.h
===================================================================
--- trunk/bibdesk/BDSKPasswordController.h 2018-02-07 07:30:32 UTC (rev
21836)
+++ trunk/bibdesk/BDSKPasswordController.h 2018-02-07 19:31:02 UTC (rev
21837)
@@ -46,11 +46,17 @@
IBOutlet NSTextField *statusField;
}
++ (NSData *)passwordForKeychainService:(NSString *)service account:(NSString
*)account name:(NSString *)name;
+
++ (BOOL)addOrModifyPassword:(NSString *)password forKeychainService:(NSString
*)service account:(NSString *)account name:(NSString *)name;
+
++ (NSData *)runModalPanelForKeychainService:(NSString *)service
account:(NSString *)account name:(NSString *)aName message:(NSString *)status;
+
+ (NSData *)passwordForKeychainServiceName:(NSString *)name;
+ (BOOL)addOrModifyPassword:(NSString *)password
forKeychainServiceName:(NSString *)name;
-+ (NSData *)runModalPanelForKeychainServiceName:(NSString *)aName
message:(NSString *)status;
++ (NSData *)runModalPanelForKeychainServiceName:(NSString *)name
message:(NSString *)status;
- (IBAction)buttonAction:(id)sender;
Modified: trunk/bibdesk/BDSKPasswordController.m
===================================================================
--- trunk/bibdesk/BDSKPasswordController.m 2018-02-07 07:30:32 UTC (rev
21836)
+++ trunk/bibdesk/BDSKPasswordController.m 2018-02-07 19:31:02 UTC (rev
21837)
@@ -44,6 +44,134 @@
@implementation BDSKPasswordController
++ (NSData *)passwordForKeychainService:(NSString *)service account:(NSString
*)account name:(NSString *)name {
+ // use the service name to get password from keychain and hash it with
sha1 for comparison purposes
+ OSStatus err;
+
+ const char *serviceCString = [service UTF8String];
+ const char *accountCString = [account UTF8String];
+ const char *nameCString = [name UTF8String];
+ void *password = NULL;
+ UInt32 passwordLength = 0;
+ NSData *pwData = nil;
+
+ // see if the password exists in the keychain
+ err = SecKeychainFindGenericPassword(NULL, strlen(serviceCString),
serviceCString, account ? strlen(accountCString) : 0, NULL, &passwordLength,
&password, NULL);
+ if (err == errSecItemNotFound && name) {
+ // see if an item in the old format exists
+ SecKeychainItemRef itemRef = nil;
+ err = SecKeychainFindGenericPassword(NULL, strlen(nameCString),
nameCString, 0, NULL, &passwordLength, &password, &itemRef);
+ if (err == noErr) {
+ // item in old format exists, update to new format
+ // default is to use current user's username
+ if (account == nil)
+ accountCString = [NSUserName() UTF8String];
+ SecKeychainAttribute attrs[] = {
+ {kSecServiceItemAttr, (SInt32)strlen(serviceCString), (void
*)serviceCString},
+ {kSecAccountItemAttr, (SInt32)strlen(accountCString), (void
*)accountCString},
+ {kSecLabelItemAttr, (SInt32)strlen(nameCString), (void
*)nameCString}};
+ SecKeychainAttributeList attributes = {3, attrs};
+ SecKeychainItemModifyAttributesAndData(itemRef, &attributes, 0,
NULL);
+ CFRelease(itemRef);
+ }
+ }
+ if (err == noErr) {
+ pwData = [NSData dataWithBytes:password length:passwordLength];
+ SecKeychainItemFreeContent(NULL, password);
+ } else if (err != errSecItemNotFound && err != errSecUserCanceled){
+ NSLog(@"Error %d occurred getting password: %@", (int)err,
[(id)SecCopyErrorMessageString(err, NULL) autorelease]);
+ }
+ return pwData;
+}
+
++ (BOOL)addOrModifyPassword:(NSString *)password forKeychainService:(NSString
*)service account:(NSString *)account name:(NSString *)name {
+
+ NSParameterAssert(service != nil);
+ NSParameterAssert(password != nil);
+ const char *serviceCString = [service UTF8String];
+ const char *accountCString = [account UTF8String];
+
+ OSStatus err;
+ SecKeychainItemRef itemRef = NULL;
+ const void *passwordData = [password UTF8String];
+ const void *oldPasswordData = NULL;
+ UInt32 passwordLength = 0;
+
+ // first see if the password exists in the keychain
+ err = SecKeychainFindGenericPassword(NULL, strlen(serviceCString),
serviceCString, account ? strlen(accountCString) : 0, NULL, &passwordLength,
(void **)&oldPasswordData, &itemRef);
+
+ if (err == noErr) {
+ // password was on keychain, so flush the buffer and then modify the
keychain if necessary
+ if (passwordLength != strlen(passwordData) || strncmp(passwordData,
oldPasswordData, passwordLength) != 0) {
+ err = SecKeychainItemModifyAttributesAndData(itemRef, NULL,
strlen(passwordData), passwordData);
+ if (err != noErr && err != errSecUserCanceled)
+ NSLog(@"Error %d occurred modifying password: %@", (int)err,
[(id)SecCopyErrorMessageString(err, NULL) autorelease]);
+ }
+ SecKeychainItemFreeContent(NULL, (void *)oldPasswordData);
+ CFRelease(itemRef);
+ } else if (err == errSecItemNotFound) {
+ // password not on keychain
+ if (name) {
+ const char *nameCString = [name UTF8String];
+
+ // see if an item in the old format exists
+ err = SecKeychainFindGenericPassword(NULL, strlen(nameCString),
nameCString, 0, NULL, NULL, NULL, &itemRef);
+
+ // default is to use current user's username
+ if (account == nil)
+ accountCString = [NSUserName() UTF8String];
+ SecKeychainAttribute attrs[] = {
+ {kSecServiceItemAttr, (SInt32)strlen(serviceCString), (void
*)serviceCString},
+ {kSecAccountItemAttr, (SInt32)strlen(accountCString), (void
*)accountCString},
+ {kSecLabelItemAttr, (SInt32)strlen(nameCString), (void
*)nameCString}};
+ SecKeychainAttributeList attributes = {3, attrs};
+ if (err == noErr) {
+ // password in old format was on keychain, modify the keychain
to the new format
+ err = SecKeychainItemModifyAttributesAndData(itemRef,
&attributes, strlen(passwordData), passwordData);
+ CFRelease(itemRef);
+ } else if (err == errSecItemNotFound) {
+ // password not on keychain, so add it
+ err =
SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes,
strlen(passwordData), passwordData, NULL, NULL, NULL);
+ } else if (err != errSecUserCanceled) {
+ NSLog(@"Error %d occurred getting password: %@", (int)err,
[(id)SecCopyErrorMessageString(err, NULL) autorelease]);
+ }
+ } else {
+ // simple password not on keychain, so add it
+ // default is to use current user's username
+ if (account == nil)
+ accountCString = [NSUserName() UTF8String];
+ err = SecKeychainAddGenericPassword(NULL, strlen(serviceCString),
serviceCString, strlen(accountCString), accountCString, strlen(passwordData),
passwordData, NULL);
+ if (err != noErr && err != errSecUserCanceled)
+ NSLog(@"Error %d occurred adding password: %@", (int)err,
[(id)SecCopyErrorMessageString(err, NULL) autorelease]);
+ }
+ } else if (err != errSecUserCanceled) {
+ NSLog(@"Error %d occurred getting password: %@", (int)err,
[(id)SecCopyErrorMessageString(err, NULL) autorelease]);
+ }
+ return (err == noErr);
+}
+
+- (NSData *)runModalForKeychainService:(NSString *)service account:(NSString
*)account name:(NSString *)name message:(NSString *)status {
+ NSString *password = nil;
+ [self window]; // load window before seting the status
+ [statusField setStringValue:status];
+ if (NSOKButton == [NSApp runModalForWindow:[self window]]) {
+ NSAssert(name != nil, @"name is nil");
+ password = [[[passwordField stringValue] retain] autorelease];
+ NSParameterAssert(password != nil);
+ [[self class] addOrModifyPassword:password forKeychainService:service
account:account name:name];
+ }
+ [[self window] orderOut:self];
+
+ if (password == nil)
+ return nil;
+ return [password dataUsingEncoding:NSUTF8StringEncoding];
+}
+
++ (NSData *)runModalPanelForKeychainService:(NSString *)service
account:(NSString *)account name:(NSString *)name message:(NSString *)status {
+ BDSKPasswordController *pwc = [[[self alloc]
initWithWindowNibName:@"BDSKPasswordController"] autorelease];
+ return [pwc runModalForKeychainService:service account:account name:name
message:status];
+}
+
+ (NSData *)passwordForKeychainServiceName:(NSString *)name {
// use the service name to get password from keychain and hash it with
sha1 for comparison purposes
OSStatus err;
Modified: trunk/bibdesk/BDSKSharingClient.m
===================================================================
--- trunk/bibdesk/BDSKSharingClient.m 2018-02-07 07:30:32 UTC (rev 21836)
+++ trunk/bibdesk/BDSKSharingClient.m 2018-02-07 19:31:02 UTC (rev 21837)
@@ -43,6 +43,8 @@
#import "NSData_BDSKExtensions.h"
#import "CFString_BDSKExtensions.h"
+static NSString *BDSKClientServiceNameForKeychain = @"BibDesk Sharing Access";
+
typedef struct _BDSKSharingClientFlags {
volatile int32_t isRetrieving;
volatile int32_t authenticationFailed;
@@ -203,10 +205,6 @@
// If we introduce incompatible changes in future, bump this to avoid sharing
breakage
+ (NSString *)supportedProtocolVersion { return @"0"; }
-+ (NSString *)keychainServiceNameWithComputerName:(NSString *)computerName {
- return [NSString stringWithFormat:@"%@ - %@", computerName,
BDSKServiceNameForKeychain];
-}
-
- (id)initWithClient:(BDSKSharingClient *)aClient andService:(NSNetService
*)aService;
{
self = [super init];
@@ -366,10 +364,17 @@
#pragma mark Authentication
+- (NSString *)keychainItemName {
+ return [NSString stringWithFormat:@"%@ - %@", [service name],
BDSKServiceNameForKeychain];
+}
+
- (NSData *)runPasswordPrompt;
{
NSAssert([NSThread isMainThread] == 1, @"password controller must be run
from the main thread");
- return [BDSKPasswordController runModalPanelForKeychainServiceName:[[self
class] keychainServiceNameWithComputerName:[service name]] message:[NSString
stringWithFormat:NSLocalizedString(@"Enter password for %@", @"Prompt for
Password dialog"), [service name]]];
+ return [BDSKPasswordController
runModalPanelForKeychainService:BDSKClientServiceNameForKeychain
+ account:[service
name]
+ name:[self
keychainItemName]
+ message:[NSString
stringWithFormat:NSLocalizedString(@"Enter password for %@", @"Prompt for
Password dialog"), [service name]]];
}
- (NSInteger)runAuthenticationFailedAlert;
@@ -394,7 +399,9 @@
OSMemoryBarrier();
if(flags.authenticationFailed == 0)
- password = [BDSKPasswordController
passwordForKeychainServiceName:[[self class]
keychainServiceNameWithComputerName:[service name]]];
+ password = [BDSKPasswordController
passwordForKeychainService:BDSKClientServiceNameForKeychain
+
account:[service name]
+
name:[self keychainItemName]];
if(password == nil && [self shouldKeepRunning]){
Modified: trunk/bibdesk/BDSKSharingServer.m
===================================================================
--- trunk/bibdesk/BDSKSharingServer.m 2018-02-07 07:30:32 UTC (rev 21836)
+++ trunk/bibdesk/BDSKSharingServer.m 2018-02-07 19:31:02 UTC (rev 21837)
@@ -685,7 +685,7 @@
{
BOOL status = YES;
if([[NSUserDefaults standardUserDefaults]
boolForKey:BDSKSharingRequiresPasswordKey]){
- NSData *myPasswordHashed = [[BDSKPasswordController
passwordForKeychainServiceName:BDSKServiceNameForKeychain] sha1Signature];
+ NSData *myPasswordHashed = [[BDSKPasswordController
passwordForKeychainService:BDSKServiceNameForKeychain account:nil name:nil]
sha1Signature];
status = [authenticationData isEqual:myPasswordHashed];
}
return status;
Modified: trunk/bibdesk/BibPref_Sharing.m
===================================================================
--- trunk/bibdesk/BibPref_Sharing.m 2018-02-07 07:30:32 UTC (rev 21836)
+++ trunk/bibdesk/BibPref_Sharing.m 2018-02-07 19:31:02 UTC (rev 21837)
@@ -86,7 +86,7 @@
- (void)willSelect {
if (didReadPassword == NO) {
didReadPassword = YES;
- NSData *pwData = [BDSKPasswordController
passwordForKeychainServiceName:BDSKServiceNameForKeychain];
+ NSData *pwData = [BDSKPasswordController
passwordForKeychainService:BDSKServiceNameForKeychain account:nil name:nil];
if(pwData != nil){
NSString *pwString = [[NSString alloc] initWithData:pwData
encoding:NSUTF8StringEncoding];
[passwordField setStringValue:pwString];
@@ -97,7 +97,7 @@
- (void)defaultsDidRevert {
// always clear the password, as that's not set in our prefs, and always
send the notifications
- [BDSKPasswordController addOrModifyPassword:@""
forKeychainServiceName:BDSKServiceNameForKeychain];
+ [BDSKPasswordController addOrModifyPassword:@""
forKeychainService:BDSKServiceNameForKeychain account:nil name:nil];
if ([sud boolForKey:BDSKShouldLookForSharedFilesKey])
[[BDSKSharingBrowser sharedBrowser] enableSharedBrowsing];
else
@@ -185,7 +185,7 @@
- (IBAction)changePassword:(id)sender
{
- if ([BDSKPasswordController addOrModifyPassword:[sender stringValue]
forKeychainServiceName:BDSKServiceNameForKeychain])
+ if ([BDSKPasswordController addOrModifyPassword:[sender stringValue]
forKeychainService:BDSKServiceNameForKeychain account:nil name:nil])
[[NSNotificationCenter defaultCenter]
postNotificationName:BDSKSharingPasswordChangedNotification object:nil];
}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Bibdesk-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bibdesk-commit