Added functions to save and get password from keychain
authorAlexandra Ellwood <lxs@mit.edu>
Thu, 18 Sep 2008 18:57:01 +0000 (18:57 +0000)
committerAlexandra Ellwood <lxs@mit.edu>
Thu, 18 Sep 2008 18:57:01 +0000 (18:57 +0000)
ticket: 6055

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@20732 dc483132-0cff-0310-8789-dd5450dbe970

src/kim/lib/kim_identity.c
src/kim/lib/kim_identity_private.h
src/kim/lib/mac/kim_os_identity.c

index 2fd8579d0d08be4aa81f1d031b575c72352c8ed2..e427a2a1bfee9004fb856ec91932f35c2964d2d6 100644 (file)
@@ -450,6 +450,57 @@ kim_error kim_identity_get_component_at_index (kim_identity  in_identity,
 
 /* ------------------------------------------------------------------------ */
 
+kim_error kim_identity_get_components (kim_identity  in_identity,
+                                       kim_string   *out_components)
+{
+    kim_error err = KIM_NO_ERROR;
+    kim_string components = NULL;
+    kim_count count, i;
+    
+    if (!err && !in_identity   ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+    if (!err && !out_components) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+    
+    if (!err) {
+        err = kim_identity_get_number_of_components (in_identity, &count);
+    }
+    
+    if (!err) {
+        err = kim_identity_get_component_at_index (in_identity, 0, &components);
+    }
+    
+    for (i = 1; !err && i < count; i++) {
+        kim_string new_components = NULL;
+        kim_string component = NULL;
+        
+        err = kim_identity_get_component_at_index (in_identity, 0, &component);
+        
+        if (!err) {
+            err = kim_string_create_from_format (&new_components, "%s/%s",
+                                                 components, component);
+        }
+        
+        if (!err) {
+            kim_string_free (&components);
+            components = new_components;
+            new_components = NULL;
+        }
+        
+        if (component     ) { kim_string_free (&component); }
+        if (new_components) { kim_string_free (&new_components); }
+    }
+    
+    if (!err) {
+        *out_components = components;
+        components = NULL;
+    }
+    
+    if (components) { kim_string_free (&components); }
+    
+    return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
 kim_error kim_identity_get_krb5_principal (kim_identity    in_identity,
                                            krb5_context    in_krb5_context,
                                            krb5_principal *out_krb5_principal)
@@ -470,32 +521,6 @@ kim_error kim_identity_get_krb5_principal (kim_identity    in_identity,
     return check_error (err);
 }
 
-/* ------------------------------------------------------------------------ */
-/*!
- * \param in_identity   an identity object.
- * \param out_gss_name  on exit, a gss_name_t representation of \a in_identity.
- *                      Must be freed with gss_release_name().
- * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
- * \brief Get the gss_name_t representation of an identity.
- */
-/*kim_error kim_identity_get_gss_name (kim_identity  in_identity,
-                                       gss_name_t     *out_gss_name);*/
-/*
-kim_error kim_identity_get_gss_name (kim_identity  in_identity,
-                                     gss_name_t   *out_gss_name)
-{
-    kim_error err = KIM_NO_ERROR;
-    
-    if (!err && !in_identity ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-    if (!err && !out_gss_name) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-    
-    if (!err) {
-#warning kim_identity_get_gss_name not implemented
-    }
-    
-    return check_error (err);
-}*/
-
 /* ------------------------------------------------------------------------ */
 
 kim_error kim_identity_is_tgt_service (kim_identity  in_identity,
@@ -528,6 +553,10 @@ kim_error kim_identity_change_password (kim_identity in_identity,
     
     if (!err && !in_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
     
+    if (!err) {
+#warning Implement change password GUI support
+    }
+
     return check_error (err);
 }
 
@@ -542,6 +571,10 @@ kim_error kim_identity_change_password_to_password (kim_identity in_identity,
     if (!err && !in_identity    ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
     if (!err && !in_new_password) { err = check_error (KIM_NULL_PARAMETER_ERR); }
     
+    if (!err) {
+#warning Implement change password support
+    }
+    
     return check_error (err);
 }
 
index 7bbbb7ce2bbe154a40f3e660baadde518a87ef5c..d22417955bebc79267a7b2dc2d9a69a19426e19f 100644 (file)
 #include <kim/kim.h>
 #include "kim_library_private.h"
 
-kim_error kim_os_identity_create_for_username (kim_identity *out_identity);
+kim_error kim_identity_get_components (kim_identity  in_identity,
+                                       kim_string   *out_components);
 
 kim_error kim_identity_is_tgt_service (kim_identity  in_identity,
                                        kim_boolean  *out_is_tgt_service);
 
+
+kim_error kim_os_identity_create_for_username (kim_identity *out_identity);
+
+kim_error kim_os_identity_get_saved_password (kim_identity  in_identity,
+                                              kim_string   *out_password);
+
+kim_error kim_os_identity_set_saved_password (kim_identity in_identity,
+                                              kim_string   in_password);
+
 #endif /* KIM_IDENTITY_PRIVATE_H */
index 18e217660f60bd5bcb830c362f071810da3952ec..c25729b75f29ee13b79d9d621b247c3a1d98c6bf 100644 (file)
 
 #include <pwd.h>
 #include <unistd.h>
+#include <Security/Security.h>
 
 #include "kim_os_private.h"
 
 /* ------------------------------------------------------------------------ */
 
+kim_error kim_os_identity_get_saved_password (kim_identity  in_identity,
+                                              kim_string   *out_password)
+{
+    kim_error err = KIM_NO_ERROR;
+    kim_string realm = NULL;
+    kim_string name = NULL;
+    void *buffer = NULL;
+    UInt32 length = 0;
+    
+    if (!err && !in_identity ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+    if (!err && !out_password) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+    
+    if (!err) {
+        err = kim_identity_get_components (in_identity, &name);
+    }
+    
+    if (!err) {
+        err = kim_identity_get_realm (in_identity, &realm);
+    }
+    
+    if (!err) {
+        err = SecKeychainFindGenericPassword (nil, 
+                                              strlen (realm), realm,
+                                              strlen (name), name,
+                                              &length, &buffer, 
+                                              nil);
+        
+        if (!err && !buffer) { err = check_error (ENOENT); }
+    }
+    
+    if (!err) {
+        err = kim_string_create_from_buffer (out_password, buffer, length);
+    }
+    
+    if (name  ) { kim_string_free (&name); }
+    if (realm ) { kim_string_free (&realm); }
+    if (buffer) { SecKeychainItemFreeContent (NULL, buffer); }
+    
+    return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+kim_error kim_os_identity_set_saved_password (kim_identity in_identity,
+                                              kim_string   in_password)
+{
+    kim_error err = KIM_NO_ERROR;
+    kim_string realm = NULL;
+    kim_string name = NULL;
+    
+    if (!err && !in_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+    if (!err && !in_password) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+    
+    if (!err) {
+        err = kim_identity_get_components (in_identity, &name);
+    }
+    
+    if (!err) {
+        err = kim_identity_get_realm (in_identity, &realm);
+    }
+    
+    if (!err) {
+        SecKeychainItemRef itemRef = NULL;
+        UInt32 namelen = strlen (name);
+        UInt32 realmlen = strlen (realm);
+        
+        // Add the password to the keychain
+        err = SecKeychainAddGenericPassword (nil, 
+                                             realmlen, realm,
+                                             namelen, name,
+                                             strlen (in_password), in_password,
+                                             &itemRef); 
+        
+        if (err == errSecDuplicateItem) {
+            // We've already stored a password for this principal
+            // but it might have changed so update it
+            void *buffer = NULL;
+            UInt32 length = 0;
+            
+            err = SecKeychainFindGenericPassword (nil, 
+                                                  realmlen, realm,
+                                                  namelen, name,
+                                                  &length, &buffer, 
+                                                  &itemRef);
+            
+            if (!err) {
+                SecKeychainAttribute attrs[] = {
+                    { kSecAccountItemAttr, namelen,  (char *) name },
+                    { kSecServiceItemAttr, realmlen, (char *) realm } };
+                UInt32 count = sizeof(attrs) / sizeof(attrs[0]);
+                const SecKeychainAttributeList attrList = { count, attrs };
+                
+                err = SecKeychainItemModifyAttributesAndData (itemRef,
+                                                              &attrList,
+                                                              strlen (in_password), 
+                                                              in_password);
+            }
+            
+        } else if (!err) {
+            // We added a new entry, add a descriptive label
+            SecKeychainAttributeList *copiedAttrs = NULL;
+            SecKeychainAttributeInfo attrInfo;
+            UInt32 tag = 7;
+            UInt32 format = CSSM_DB_ATTRIBUTE_FORMAT_STRING;
+            kim_string label = NULL;
+            
+            attrInfo.count = 1;
+            attrInfo.tag = &tag;
+            attrInfo.format = &format;
+            
+            err = SecKeychainItemCopyAttributesAndData (itemRef, &attrInfo, NULL, 
+                                                        &copiedAttrs, 0, NULL);
+            
+            if (!err) {
+                /* Label format used by Apple patches */
+                err = kim_string_create_from_format (&label, "%s (%s)", 
+                                                     realm, name);
+            }
+            
+            if (!err) {
+                SecKeychainAttributeList attrList;
+                SecKeychainAttribute attr;
+                
+                /* Copy the tag they gave us and copy in our label */
+                attr.tag = copiedAttrs->attr->tag;
+                attr.length = strlen (label);
+                attr.data = (char *) label;
+                
+                attrList.count = 1;
+                attrList.attr = &attr;
+                
+                /* And modify. */
+                err = SecKeychainItemModifyAttributesAndData (itemRef, &attrList, 
+                                                              0, NULL);
+            }
+            
+            if (label      ) { kim_string_free (&label); }
+            if (copiedAttrs) { SecKeychainItemFreeAttributesAndData (copiedAttrs, NULL); }            
+        }
+        
+        if (itemRef) { CFRelease (itemRef); }
+    }
+    
+    if (name ) { kim_string_free (&name); }
+    if (realm) { kim_string_free (&realm); }
+    
+    return check_error (err);
+}    
+
+/* ------------------------------------------------------------------------ */
+
 kim_error kim_os_identity_create_for_username (kim_identity *out_identity)
 {
     kim_error err = KIM_NO_ERROR;