/* ------------------------------------------------------------------------ */
+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)
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,
if (!err && !in_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err) {
+#warning Implement change password GUI support
+ }
+
return check_error (err);
}
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);
}
#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;