Index: AppController.m
===================================================================
--- AppController.m	(revision 196)
+++ AppController.m	(working copy)
@@ -75,6 +75,8 @@
   NSDictionary *sshfsEnv = [NSDictionary dictionaryWithObjectsAndKeys:
     @"NONE", @"DISPLAY", // I know "NONE" is bogus; I just need something
     askPassPath, @"SSH_ASKPASS",
+    username, @"SSHFS_USER",
+    server, @"SSHFS_SERVER",
     nil];
     
   NSArray *sshfsArgs = [NSArray arrayWithObjects:
Index: sshfs.xcodeproj/project.pbxproj
===================================================================
--- sshfs.xcodeproj/project.pbxproj	(revision 196)
+++ sshfs.xcodeproj/project.pbxproj	(working copy)
@@ -7,6 +7,7 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		3D1E40020B6CC2E30061E025 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D1E40010B6CC2E30061E025 /* Security.framework */; };
 		8205AF7A0B653F3700A99579 /* sshfs-static in Resources */ = {isa = PBXBuildFile; fileRef = 8205AF790B653F3700A99579 /* sshfs-static */; };
 		823578210B44701F00FE77BB /* ssh.icns in Resources */ = {isa = PBXBuildFile; fileRef = 823578200B44701F00FE77BB /* ssh.icns */; };
 		8235784C0B44782400FE77BB /* askpass.c in Sources */ = {isa = PBXBuildFile; fileRef = 8235784B0B44782400FE77BB /* askpass.c */; };
@@ -37,6 +38,7 @@
 		29B97316FDCFA39411CA2CEA /* sshfsMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = sshfsMain.m; sourceTree = "<group>"; };
 		29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
 		32CA4F630368D1EE00C91783 /* sshfs.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sshfs.pch; sourceTree = "<group>"; };
+		3D1E40010B6CC2E30061E025 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
 		8205AF790B653F3700A99579 /* sshfs-static */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = "sshfs-static"; path = "Resources/sshfs-static"; sourceTree = "<group>"; };
 		823578200B44701F00FE77BB /* ssh.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = ssh.icns; path = Resources/ssh.icns; sourceTree = "<group>"; };
 		823578420B4477D800FE77BB /* askpass */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = askpass; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -59,6 +61,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				823578540B44786400FE77BB /* CoreFoundation.framework in Frameworks */,
+				3D1E40020B6CC2E30061E025 /* Security.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -113,6 +116,7 @@
 		29B97323FDCFA39411CA2CEA /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				3D1E40010B6CC2E30061E025 /* Security.framework */,
 				823578530B44786400FE77BB /* CoreFoundation.framework */,
 				1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
 				29B97325FDCFA39411CA2CEA /* Foundation.framework */,
Index: askpass.c
===================================================================
--- askpass.c	(revision 196)
+++ askpass.c	(working copy)
@@ -12,8 +12,99 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// Keychain management by Jan Lehnardt <jan@php.net>
+
+#define SSHFS_USER "SSHFS_USER"
+#define SSHFS_SERVER "SSHFS_SERVER"
+
 #include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
 
+char *SSHFSGetPasswordForUserAndServer(const char *user, const char *server);
+void SSHFSSavePasswordToKeychain(const char *user, const char *server, const char *password);
+
+char *SSHFSGetPasswordForUserAndServer(const char *user, const char *server)
+{
+  OSStatus result;
+  char *password;
+  UInt32 passwordLength;
+  SecKeychainItemRef item = NULL;
+
+  result = SecKeychainFindInternetPassword(
+                                          NULL, //default keychain
+                                          strlen(server), // servername length
+                                          server,
+                                          0, NULL, // security domain
+                                          strlen(user), 
+                                          user,
+                                          0, NULL, //path
+                                          22, kSecProtocolTypeSSH, //port'n'type
+                                          kSecAuthenticationTypeDefault,
+                                          &passwordLength,
+                                          (void **) &password,
+                                          &item
+                                          );
+  if(result == 0) {
+    return password;
+  }
+  
+  return "";
+}
+
+void SSHFSSavePasswordToKeychain(const char *user, const char *server, const char *password)
+{
+    OSStatus result;
+    SecKeychainItemRef item;
+
+    result = SecKeychainFindInternetPassword(
+                                          NULL, //default keychain
+                                          strlen(server), // servername length
+                                          server,
+                                          0, NULL, // security domain
+                                          strlen(user), 
+                                          user,
+                                          0, NULL, //path
+                                          22, kSecProtocolTypeSSH, //port'n'type
+                                          kSecAuthenticationTypeDefault,
+                                          0,
+                                          NULL,
+                                          &item
+                                          );
+  if (result == noErr) {
+    //update info
+    SecKeychainAttribute attributes;
+    SecKeychainAttributeList attributesList;
+
+    attributes.tag = kSecAccountItemAttr;
+    attributes.length = strlen(user);
+    attributes.data = (char *)user;
+
+    attributesList.count = 1;
+    attributesList.attr = &attributes;
+
+    result = SecKeychainItemModifyContent(item, &attributesList, strlen(password), (void *)password);
+    CFRelease(item);
+
+  } else {
+    //add info
+    result = SecKeychainAddInternetPassword(
+                                          NULL, //default keychain
+                                          strlen(server), // servername length
+                                          server,
+                                          0, NULL, // security domain
+                                          strlen(user), 
+                                          user,
+                                          0, NULL, //path
+                                          22, kSecProtocolTypeSSH, //port'n'type
+                                          kSecAuthenticationTypeDefault,
+                                          strlen(password),
+                                          password,
+                                          &item
+                                          );
+    CFRelease(item);
+  }
+}
+
 int main() {
   CFUserNotificationRef passwordDialog;
   SInt32 error;
@@ -21,75 +112,140 @@
   CFOptionFlags responseFlags;
   int button;
   CFStringRef passwordRef;
+  int savePassword = 0;
   CFIndex passwordMaxSize;
   char *password;
+  static void* keys;
+  static void* values;
   
-  CFBundleRef myBundle = CFBundleGetMainBundle();
-  CFURLRef myURL = CFBundleCopyExecutableURL(myBundle);
-  CFURLRef myParentURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault,
-                                                                  myURL);
-  CFRelease(myURL);
-  CFURLRef myIconURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
-                                                             myParentURL,
-                                                             CFSTR("ssh.icns"),
-                                                             false);
-  CFRelease(myParentURL);
+  //look for SSHFS_USER and SSHFS_SERVER in env
+  const char *sshfs_user, *sshfs_server;
+  sshfs_user = getenv(SSHFS_USER);
+  sshfs_server = getenv(SSHFS_SERVER);
+
+  int keychainEnable = 1;
+  int freePassword = 0; // 0 = no, 1 = SecKeychainItemFreeContent(), 2 = free()
+
+  if(!sshfs_user || !sshfs_server) {
+    keychainEnable = 0;
+  } else {
+    password = SSHFSGetPasswordForUserAndServer(sshfs_user, sshfs_server);
+  }
+
+  if(keychainEnable && strlen(password) > 0) {
+    freePassword = 1; // use SecKeychainItemFreeContent()
+    //done
+  } else {
+    CFBundleRef myBundle = CFBundleGetMainBundle();
+    CFURLRef myURL = CFBundleCopyExecutableURL(myBundle);
+    CFURLRef myParentURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault,
+                                                                    myURL);
+    CFRelease(myURL);
+    CFURLRef myIconURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
+                                                               myParentURL,
+                                                               CFSTR("ssh.icns"),
+                                                               false);
+    CFRelease(myParentURL);
+
+    const void* noKeychainKeys[] = {
+      kCFUserNotificationAlertHeaderKey,
+      kCFUserNotificationTextFieldTitlesKey,
+      kCFUserNotificationAlternateButtonTitleKey,
+      kCFUserNotificationIconURLKey
+    };
+
+    const void* noKeychainValues[] = {
+      CFSTR("sshfs Password"),
+      CFSTR(""),
+      CFSTR("Cancel"),
+      myIconURL
+    };
+
+    const void* keychainKeys[] = {
+      kCFUserNotificationAlertHeaderKey,
+      kCFUserNotificationTextFieldTitlesKey,
+      kCFUserNotificationCheckBoxTitlesKey,
+      kCFUserNotificationAlternateButtonTitleKey,
+      kCFUserNotificationIconURLKey
+    };
+
+    const void* keychainValues[] = {
+      CFSTR("sshfs Password"),
+      CFSTR(""),
+      CFSTR("Save in Keychain"),
+      CFSTR("Cancel"),
+      myIconURL
+    };
+
+    if(keychainEnable) {
+      keys = keychainKeys;
+      values = keychainValues;
+    } else {
+      keys = noKeychainKeys;
+      values = noKeychainValues;
+    }
+
+    dialogTemplate = CFDictionaryCreate(kCFAllocatorDefault,
+                                        keys,
+                                        values,
+                                        sizeof(keys)/sizeof(*keys),
+                                        &kCFTypeDictionaryKeyCallBacks,
+                                        &kCFTypeDictionaryValueCallBacks);
+    CFRelease(myIconURL);
   
-  const void* keys[] = {
-    kCFUserNotificationAlertHeaderKey,
-    kCFUserNotificationTextFieldTitlesKey,
-    kCFUserNotificationAlternateButtonTitleKey,
-    kCFUserNotificationIconURLKey
-  };
-  const void* values[] = {
-    CFSTR("sshfs Password"),
-    CFSTR(""),
-    CFSTR("Cancel"),
-    myIconURL
-  };
-  dialogTemplate = CFDictionaryCreate(kCFAllocatorDefault,
-                                      keys,
-                                      values,
-                                      sizeof(keys)/sizeof(*keys),
-                                      &kCFTypeDictionaryKeyCallBacks,
-                                      &kCFTypeDictionaryValueCallBacks);
-  CFRelease(myIconURL);
+    passwordDialog = CFUserNotificationCreate(kCFAllocatorDefault,
+                                              0,
+                                              kCFUserNotificationPlainAlertLevel
+                                               |
+                                              CFUserNotificationSecureTextField(0),
+                                              &error,
+                                              dialogTemplate);
   
-  passwordDialog = CFUserNotificationCreate(kCFAllocatorDefault,
-                                            0,
-                                            kCFUserNotificationPlainAlertLevel
-                                             |
-                                            CFUserNotificationSecureTextField(0),
-                                            &error,
-                                            dialogTemplate);
+    if (error)
+      return error;
   
-  if (error)
-    return error;
+    error = CFUserNotificationReceiveResponse(passwordDialog,
+                                              0,
+                                              &responseFlags);
+    if (error)
+      return error;
   
-  error = CFUserNotificationReceiveResponse(passwordDialog,
-                                            0,
-                                            &responseFlags);
-  if (error)
-    return error;
+    button = responseFlags & 0x3;
+    if (button == kCFUserNotificationAlternateResponse)
+      return 1;
+
+    if(keychainEnable) {
+      savePassword = (responseFlags & CFUserNotificationCheckBoxChecked(0));
+    }
+
+    passwordRef = CFUserNotificationGetResponseValue(passwordDialog,
+                                                     kCFUserNotificationTextFieldValuesKey,
+                                                     0);
   
-  button = responseFlags & 0x3;
-  if (button == kCFUserNotificationAlternateResponse)
-    return 1;
-  
-  passwordRef = CFUserNotificationGetResponseValue(passwordDialog,
-                                                   kCFUserNotificationTextFieldValuesKey,
-                                                   0);
-  
-  passwordMaxSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(passwordRef),
-                                                      kCFStringEncodingUTF8);
-  password = malloc(passwordMaxSize);
-  CFStringGetCString(passwordRef,
-                     password,
-                     passwordMaxSize,
-                     kCFStringEncodingUTF8);
-  CFRelease(passwordDialog);
-  
+    passwordMaxSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(passwordRef),
+                                                        kCFStringEncodingUTF8);
+    password = malloc(passwordMaxSize);
+    CFStringGetCString(passwordRef,
+                       password,
+                       passwordMaxSize,
+                       kCFStringEncodingUTF8);
+    CFRelease(passwordDialog);
+    freePassword = 2; // use free()
+    
+    if(keychainEnable && savePassword) {
+      SSHFSSavePasswordToKeychain(sshfs_user, sshfs_server, password);
+    }
+  }
+
   printf("%s", password);
-  free(password);
+
+  if(freePassword == 1) {
+      SecKeychainItemFreeContent(NULL, password);
+  }
+
+  if(freePassword == 2) {
+      free(password);
+  }
+
   return 0;
 }
