/* * gitx_askpasswd_main.m * GitX * * Created by Uli Kusterer on 19.02.10. * Copyright 2010 The Void Software. All rights reserved. * */ #include #import #include #include #include #include #include #include #include #include #include #include #include #define OKBUTTONWIDTH 100.0 #define OKBUTTONHEIGHT 24.0 #define CANCELBUTTONWIDTH 100.0 #define CANCELBUTTONHEIGHT 24.0 #define PASSHEIGHT 22.0 #define PASSLABELHEIGHT 16.0 #define WINDOWAUTOSAVENAME @"GitXAskPasswordWindowFrame" @interface GAPAppDelegate : NSObject /**/ { } @end NSString* url; OSStatus StorePasswordKeychain (const char *url, UInt32 urlLength, void* password,UInt32 passwordLength); @implementation GAPAppDelegate -(void)yesNo:(NSString *)prompt url:(NSString *)url{ NSAlert *alert = [[NSAlert alloc] init]; [alert addButtonWithTitle:@"YES"]; [alert addButtonWithTitle:@"NO"]; [alert setMessageText:[NSString stringWithFormat:@"%@?",url]]; [alert setInformativeText:prompt]; [alert setAlertStyle:NSWarningAlertStyle]; NSInteger result = [alert runModal]; Boolean yes=NO; if ( result == NSAlertFirstButtonReturn ) { yes=YES; } [alert release]; printf("%s",yes?"yes":"no"); } - (void)pasword:(NSString *)prompt url:(NSString *)url{ NSRect box = NSMakeRect(0, 0, 200, 24); NSSecureTextField * passView = [[NSSecureTextField alloc] initWithFrame: box]; [passView setSelectable: YES]; [passView setEditable: YES]; [passView setBordered: YES]; [passView setBezeled: YES]; [passView setBezelStyle: NSTextFieldSquareBezel]; [passView selectText: self]; NSAlert *alert = [[NSAlert alloc] init]; [alert addButtonWithTitle:@"Ok"]; [alert addButtonWithTitle:@"cancel"]; [alert setMessageText:[NSString stringWithFormat:@"%@?",url]]; [alert setInformativeText:prompt]; [alert setAlertStyle:NSWarningAlertStyle]; [alert setAccessoryView:passView]; [alert setShowsSuppressionButton:YES]; [[alert suppressionButton] setTitle:@"Save on keychain"]; NSInteger result = [alert runModal]; if ( result == NSAlertFirstButtonReturn ) { NSString *pas=[passView stringValue]; printf( "%s", [pas UTF8String] ); if ([[alert suppressionButton] state] == NSOnState) { StorePasswordKeychain ([url cStringUsingEncoding:NSASCIIStringEncoding], [url lengthOfBytesUsingEncoding:NSASCIIStringEncoding], (void *)[pas cStringUsingEncoding:NSASCIIStringEncoding], [pas lengthOfBytesUsingEncoding:NSASCIIStringEncoding]); } } [alert release]; } @end void getproclline(pid_t pid, char *command_name); void getproclline(pid_t pid, char *command_name) { int mib[3], argmax, nargs, c = 0; size_t size; char *procargs, *sp, *np, *cp; mib[0] = CTL_KERN; mib[1] = KERN_ARGMAX; size = sizeof(argmax); if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) { return; } /* Allocate space for the arguments. */ procargs = (char *)malloc(argmax); if (procargs == NULL) { return; } mib[0] = CTL_KERN; mib[1] = KERN_PROCARGS2; mib[2] = pid; size = (size_t)argmax; if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) { return; } memcpy(&nargs, procargs, sizeof(nargs)); cp = procargs + sizeof(nargs); /* Skip the saved exec_path. */ for (; cp < &procargs[size]; cp++) { if (*cp == '\0') { /* End of exec_path reached. */ break; } } if (cp == &procargs[size]) { return; } /* Skip trailing '\0' characters. */ for (; cp < &procargs[size]; cp++) { if (*cp != '\0') { /* Beginning of first argument reached. */ break; } } if (cp == &procargs[size]) { return; } /* Save where the argv[0] string starts. */ sp = cp; for (np = NULL; c < nargs && cp < &procargs[size]; cp++) { if (*cp == '\0') { c++; if (np != NULL) { *np = ' '; } np = cp; } } sprintf(command_name, "%s",sp); } OSStatus StorePasswordKeychain (const char *url, UInt32 urlLength, void* password,UInt32 passwordLength) { OSStatus status; status = SecKeychainAddGenericPassword ( NULL, // default keychain 4, // length of service name "GitX", // service name urlLength, // length of account name url, // account name passwordLength, // length of password password, // pointer to password data NULL // the item reference ); return (status); } OSStatus GetPasswordKeychain (const char *url, UInt32 urlLength ,void *passwordData,UInt32 *passwordLength, SecKeychainItemRef *itemRef) { OSStatus status ; status = SecKeychainFindGenericPassword ( NULL, // default keychain 4, // length of service name "GitX", // service name urlLength, // length of account name url, // account name passwordLength, // length of password passwordData, // pointer to password data itemRef // the item reference ); return (status); } int main( int argc, const char* argv[] ) { // close stderr to stop cocoa log messages from being picked up by GitX close(STDERR_FILENO); ProcessSerialNumber myPSN = { 0, kCurrentProcess }; TransformProcessType( &myPSN, kProcessTransformToForegroundApplication ); NSApplication *app = [NSApplication sharedApplication]; GAPAppDelegate *appDel = [[GAPAppDelegate alloc] init]; [app setDelegate: appDel]; char args[4024]; getproclline(getppid(),args); NSString *cmd=[NSString stringWithFormat:@"%@",[NSString stringWithUTF8String:args]]; NSLog(@"cmd: '%@'",cmd); if([cmd hasPrefix:@"git-remote"]){ NSArray *args=[cmd componentsSeparatedByString:@" "]; NSString *url=[args objectAtIndex:[args count]-1]; void *passwordData = nil; SecKeychainItemRef itemRef = nil; UInt32 passwordLength = 0; OSStatus status = GetPasswordKeychain ([url cStringUsingEncoding:NSASCIIStringEncoding],[url lengthOfBytesUsingEncoding:NSASCIIStringEncoding],&passwordData,&passwordLength,&itemRef); if (status == noErr) { SecKeychainItemFreeContent (NULL,passwordData); NSString *pas=[[NSString stringWithCString:passwordData encoding:NSASCIIStringEncoding] substringToIndex:passwordLength]; printf( "%s", [pas UTF8String] ); return 0; } NSString *prompt=[NSString stringWithFormat:@"%@",[NSString stringWithCString:argv[1] encoding:NSASCIIStringEncoding]]; [appDel pasword:prompt url:url]; }else{ // yes/no? NSString *prompt=[NSString stringWithFormat:@"%@",[NSString stringWithCString:argv[1] encoding:NSASCIIStringEncoding]]; NSArray *args=[cmd componentsSeparatedByString:@" "]; NSString *url=[args objectAtIndex:1]; [appDel yesNo:prompt url:url]; } return 0; }