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

Reply via email to