From 9593756e59a4e4f7b3ac44a92031c8852445bba5 Mon Sep 17 00:00:00 2001 From: Alexandra Ellwood Date: Wed, 17 Sep 2008 21:29:35 +0000 Subject: [PATCH] Added support for options in favorite identities. Fixed KLL preference reading support to not read keys from the wrong locations. Updated prompter function prototype. Updated tests to reflect these changes. ticket: 6055 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@20727 dc483132-0cff-0310-8789-dd5450dbe970 --- src/include/kim/kim_options.h | 84 +- src/kim/lib/kim-lite.exports | 2 - src/kim/lib/kim_options.c | 95 +-- src/kim/lib/kim_options_private.h | 2 +- src/kim/lib/kim_preferences.c | 170 +--- src/kim/lib/kim_preferences_private.h | 14 +- src/kim/lib/mac/kim_os_preferences.c | 1028 +++++++++++++++++++------ src/kim/test/main.c | 2 + src/kim/test/test_kim_preferences.c | 187 ++++- src/kim/test/test_kim_preferences.h | 2 + 10 files changed, 1036 insertions(+), 550 deletions(-) diff --git a/src/include/kim/kim_options.h b/src/include/kim/kim_options.h index fd6efdf47..f5b975cf3 100644 --- a/src/include/kim/kim_options.h +++ b/src/include/kim/kim_options.h @@ -62,45 +62,41 @@ enum kim_prompt_type_enum { * The prompt callback used to display a prompt to the user. * See \ref kim_options_custom_prompt_callback for more information. */ -typedef kim_error (*kim_prompt_callback) (kim_options *io_options, - kim_prompt_type in_type, +typedef kim_error (*kim_prompt_callback) (kim_prompt_type in_type, kim_string in_title, kim_string in_message, kim_string in_description, - void **out_reply); + char **out_reply); /*! * The default prompt callback. * See \ref kim_options_custom_prompt_callback for more information. */ -kim_error kim_prompt_callback_default (kim_options *io_options, - kim_prompt_type in_type, +kim_error kim_prompt_callback_default (kim_prompt_type in_type, kim_string in_title, kim_string in_message, kim_string in_description, - void **out_reply); + char **out_reply); /*! * The graphical prompt callback. * See \ref kim_options_custom_prompt_callback for more information. */ -kim_error kim_prompt_callback_gui (kim_options *io_options, - kim_prompt_type in_type, +kim_error kim_prompt_callback_gui (kim_prompt_type in_type, kim_string in_title, kim_string in_message, kim_string in_description, - void **out_reply); + char **out_reply); /*! * The command line prompt callback. * See \ref kim_options_custom_prompt_callback for more information. */ -kim_error kim_prompt_callback_cli (kim_options *io_options, - kim_prompt_type in_type, +kim_error kim_prompt_callback_cli (kim_prompt_type in_type, kim_string in_title, kim_string in_message, kim_string in_description, - void **out_reply); + char **out_reply); /*! * The prompt callback which always returns an error. @@ -108,12 +104,11 @@ kim_error kim_prompt_callback_cli (kim_options *io_options, * \note Using this callback may prevent the user from authenicating. * See \ref kim_options_custom_prompt_callback for more information. */ -kim_error kim_prompt_callback_none (kim_options *io_options, - kim_prompt_type in_type, +kim_error kim_prompt_callback_none (kim_prompt_type in_type, kim_string in_title, kim_string in_message, kim_string in_description, - void **out_reply); + char **out_reply); /*! @} */ @@ -143,7 +138,7 @@ kim_error kim_prompt_callback_none (kim_options *io_options, * \subsection kim_options_custom_prompt_callback Providing a Custom Prompt Callback * * All secrets are obtained from the user through a #kim_prompt_callback_t. By default, - * options use #kim_prompt_callback_default, which presents an expanding dialog to request + * options use #kim_prompt_callback_default, which presents a dialog to request * information from the user, or if no graphical access is available, a command line prompt. * * KIM also provides three other callbacks: #kim_prompt_callback_gui only presents @@ -154,28 +149,11 @@ kim_error kim_prompt_callback_none (kim_options *io_options, * Using #kim_options_set_prompt_callback(), you can change the prompt callback to one of * the above callbacks or a callback you have defined yourself. Callbacks are called in a * loop, one for each prompt. Because network traffic may occur between calls to the prompt - * callback, your prompt interface should support time passing between calls to the prompter. + * callback, your prompt interface should support time passing between calls to the prompter. * If you are defining a callback yourself, you should also set your own options data with * #kim_options_set_data() for storing state between calls. Options data is a caller * defined pointer value -- the Kerberos libaries make no use of it. * - * \subsection kim_options_preset_prompts Prefetching Prompt Responses - * - * Sometimes you may have already collected some of the information needed to acquire - * Kerberos credentials. Rather than creating a prompt callback, you may also prefetch - * responses to the options directly with #kim_options_set_prompt_response(). Once you - * have associated your response with a given prompt type, the Kerberos libraries will - * use this response for the first prompt of that type rather than calling the prompt - * callback to obtain it. - * - * Note that even if you prefetch responses, the prompt callback may still be called if - * you did not provide all the information required for the identity. You may specify - * the #kim_prompt_callback_none prompt callback to prevent prompting from occuring entirely, - * however, doing so will tie your application to a particular Kerberos configuration. - * For example, if your application assumes that all identities only require a password, - * it will not be able to acquire credentials at sites using SecurID pins. - * - * * \section kim_options_credential_properties Options for Controlling Credential Properties * * Kerberos credentials have a number of different properties which can be requested @@ -362,44 +340,6 @@ kim_error kim_options_set_data (kim_options io_options, kim_error kim_options_get_data (kim_options in_options, const void **out_data); -/*! - * \param io_options an options object to modify. - * \param in_prompt_type a type of prompt. - * \param in_response a response to prompts of \a in_prompt_type. - * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure. - * \brief Set a response for a prompt for use when acquiring credentials. - * \note Each response only overrides the first prompt of a given prompt type. If multiple - * prompts of the same type are required, or if a prompt of a different type is requested, - * the prompt callback will be called to obtain user input. If you want to turn off prompting - * entirely, call #kim_options_set_prompt_callback() with #kim_prompt_callback_none. - * \par Default value - * NULL (no response is set by default) - * \sa kim_options_get_prompt_response() - */ -kim_error kim_options_set_prompt_response (kim_options io_options, - kim_prompt_type in_prompt_type, - void *in_response); - -/*! - * \param in_options an options object. - * \param in_prompt_type a type of prompt. - * \param out_response on exit, the response to prompts of type \a in_prompt_type specified - * by \a in_options. Does not need to be freed but may become invalid - * when \a in_options is freed. - * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure. - * \brief Get the response for a prompt for use when acquiring credentials. - * \note Each response only overrides the first prompt of a given prompt type. If multiple - * prompts of the same type are required, or if a prompt of a different type is requested, - * the prompt callback will be called to obtain user input. If you want to turn off prompting - * entirely, call #kim_options_set_prompt_callback() with #kim_prompt_callback_none. - * \par Default value - * NULL (no response is set by default) - * \sa kim_options_set_prompt_response() - */ -kim_error kim_options_get_prompt_response (kim_options in_options, - kim_prompt_type in_prompt_type, - void **out_response); - /*! * \param io_options an options object to modify. * \param in_start_time a start date (in seconds since January 1, 1970). Set to diff --git a/src/kim/lib/kim-lite.exports b/src/kim/lib/kim-lite.exports index d9b277c27..44a428dac 100644 --- a/src/kim/lib/kim-lite.exports +++ b/src/kim/lib/kim-lite.exports @@ -31,8 +31,6 @@ kim_options_set_prompt_callback kim_options_get_prompt_callback kim_options_set_data kim_options_get_data -kim_options_set_prompt_response -kim_options_get_prompt_response kim_options_set_start_time kim_options_get_start_time kim_options_set_lifetime diff --git a/src/kim/lib/kim_options.c b/src/kim/lib/kim_options.c index f210bb4fa..dbb024c2d 100644 --- a/src/kim/lib/kim_options.c +++ b/src/kim/lib/kim_options.c @@ -31,7 +31,6 @@ struct kim_options_opaque { kim_prompt_callback prompt_callback; const void *prompt_callback_data; -#warning add prompt responses here kim_time start_time; kim_lifetime lifetime; kim_boolean renewable; @@ -80,25 +79,9 @@ static inline kim_error kim_options_allocate (kim_options *out_options) /* ------------------------------------------------------------------------ */ -kim_error kim_options_create_from_defaults (kim_options *out_options) +kim_error kim_options_create_empty (kim_options *out_options) { - kim_error err = KIM_NO_ERROR; - kim_options options = NULL; - - if (!err && !out_options) { err = check_error (KIM_NULL_PARAMETER_ERR); } - - if (!err) { - err = kim_options_allocate (&options); - } - - if (!err) { - *out_options = options; - options = NULL; - } - - kim_options_free (&options); - - return check_error (err); + return check_error (kim_options_allocate (out_options)); } /* ------------------------------------------------------------------------ */ @@ -140,7 +123,6 @@ kim_error kim_options_copy (kim_options *out_options, if (!err) { options->prompt_callback = in_options->prompt_callback; options->prompt_callback_data = in_options->prompt_callback_data; -#warning copy prompt responses here } if (!err) { @@ -238,42 +220,6 @@ kim_error kim_options_get_data (kim_options in_options, /* ------------------------------------------------------------------------ */ -kim_error kim_options_set_prompt_response (kim_options io_options, - kim_prompt_type in_prompt_type, - void *in_response) -{ - kim_error err = KIM_NO_ERROR; - - if (!err && !io_options ) { err = check_error (KIM_NULL_PARAMETER_ERR); } - if (!err && !in_response) { err = check_error (KIM_NULL_PARAMETER_ERR); } - - if (!err) { -#warning kim_options_set_prompt_response unimplemented - } - - return check_error (err); -} - -/* ------------------------------------------------------------------------ */ - -kim_error kim_options_get_prompt_response (kim_options in_options, - kim_prompt_type in_prompt_type, - void **out_response) -{ - kim_error err = KIM_NO_ERROR; - - if (!err && !in_options ) { err = check_error (KIM_NULL_PARAMETER_ERR); } - if (!err && !out_response) { err = check_error (KIM_NULL_PARAMETER_ERR); } - - if (!err) { -#warning kim_options_get_prompt_response unimplemented - } - - return check_error (err); -} - -/* ------------------------------------------------------------------------ */ - kim_error kim_options_set_start_time (kim_options io_options, kim_time in_start_time) { @@ -514,7 +460,7 @@ kim_error kim_options_set_service_name (kim_options io_options, if (!err && !io_options ) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && !in_service_name) { err = check_error (KIM_NULL_PARAMETER_ERR); } - if (!err) { + if (!err && in_service_name) { err = kim_string_copy (&service_name, in_service_name); } @@ -537,7 +483,11 @@ kim_error kim_options_get_service_name (kim_options in_options, if (!err && !out_service_name) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { - err = kim_string_copy (out_service_name, in_options->service_name); + if (in_options->service_name) { + err = kim_string_copy (out_service_name, in_options->service_name); + } else { + *out_service_name = NULL; + } } return check_error (err); @@ -616,17 +566,15 @@ void kim_options_free (kim_options *io_options) /* ------------------------------------------------------------------------ */ -kim_error kim_prompt_callback_default (kim_options *io_options, - kim_prompt_type in_type, +kim_error kim_prompt_callback_default (kim_prompt_type in_type, kim_string in_title, kim_string in_message, kim_string in_description, - void **out_reply) + char **out_reply) { kim_error err = KIM_NO_ERROR; - if (!err && !io_options) { err = check_error (KIM_NULL_PARAMETER_ERR); } - if (!err && !out_reply ) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !out_reply) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { } @@ -636,17 +584,15 @@ kim_error kim_prompt_callback_default (kim_options *io_options, /* ------------------------------------------------------------------------ */ -kim_error kim_prompt_callback_gui (kim_options *io_options, - kim_prompt_type in_type, +kim_error kim_prompt_callback_gui (kim_prompt_type in_type, kim_string in_title, kim_string in_message, kim_string in_description, - void **out_reply) + char **out_reply) { kim_error err = KIM_NO_ERROR; - if (!err && !io_options) { err = check_error (KIM_NULL_PARAMETER_ERR); } - if (!err && !out_reply ) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !out_reply) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { } @@ -656,17 +602,15 @@ kim_error kim_prompt_callback_gui (kim_options *io_options, /* ------------------------------------------------------------------------ */ -kim_error kim_prompt_callback_cli (kim_options *io_options, - kim_prompt_type in_type, +kim_error kim_prompt_callback_cli (kim_prompt_type in_type, kim_string in_title, kim_string in_message, kim_string in_description, - void **out_reply) + char **out_reply) { kim_error err = KIM_NO_ERROR; - if (!err && !io_options) { err = check_error (KIM_NULL_PARAMETER_ERR); } - if (!err && !out_reply ) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !out_reply) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { } @@ -676,12 +620,11 @@ kim_error kim_prompt_callback_cli (kim_options *io_options, /* ------------------------------------------------------------------------ */ -kim_error kim_prompt_callback_none (kim_options *io_options, - kim_prompt_type in_type, +kim_error kim_prompt_callback_none (kim_prompt_type in_type, kim_string in_title, kim_string in_message, kim_string in_description, - void **out_reply) + char **out_reply) { return KIM_USER_CANCELED_ERR; } diff --git a/src/kim/lib/kim_options_private.h b/src/kim/lib/kim_options_private.h index 8dbe0a30e..f11d414ef 100644 --- a/src/kim/lib/kim_options_private.h +++ b/src/kim/lib/kim_options_private.h @@ -29,7 +29,7 @@ #include -kim_error kim_options_create_from_defaults (kim_options *out_options); +kim_error kim_options_create_empty (kim_options *out_options); kim_error kim_options_get_init_cred_options (kim_options in_options, krb5_context in_context, diff --git a/src/kim/lib/kim_preferences.c b/src/kim/lib/kim_preferences.c index 6b1fb5cc9..8ec5fd16c 100644 --- a/src/kim/lib/kim_preferences.c +++ b/src/kim/lib/kim_preferences.c @@ -54,7 +54,7 @@ struct kim_preferences_opaque { const struct kim_favorites_opaque kim_default_favorites = { 0, NULL, NULL }; struct kim_preferences_opaque kim_preferences_initializer = { -NULL, +KIM_OPTIONS_DEFAULT, FALSE, kim_default_remember_options, FALSE, @@ -184,6 +184,8 @@ kim_error kim_favorites_get_identity_at_index (kim_favorites in_favorites, kim_options *out_options) { kim_error err = KIM_NO_ERROR; + kim_identity identity = NULL; + kim_options options = KIM_OPTIONS_DEFAULT; if (!err && !in_favorites) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && !out_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); } @@ -197,10 +199,26 @@ kim_error kim_favorites_get_identity_at_index (kim_favorites in_favorites, } if (!err) { - err = kim_identity_copy (out_identity, - in_favorites->identities[in_index]); + err = kim_identity_copy (&identity, in_favorites->identities[in_index]); + } + + if (!err && in_favorites->options[in_index]) { + err = kim_options_copy (&options, in_favorites->options[in_index]); + } + + if (!err) { + *out_identity = identity; + identity = NULL; + + if (out_options) { + *out_options = options; + options = NULL; + } } + kim_identity_free (&identity); + kim_options_free (&options); + return check_error (err); } @@ -233,13 +251,14 @@ kim_error kim_favorites_add_identity (kim_favorites io_favorites, for (i = 0; !err && i < io_favorites->count; i++) { kim_comparison identity_comparison = 0; - err = kim_identity_compare (in_identity, - io_favorites->identities[i], + err = kim_identity_compare (io_favorites->identities[i], + in_identity, &identity_comparison); if (!err) { if (kim_comparison_is_greater_than (identity_comparison)) { - break; /* found the first greater one so insert here */ + /* insert before the first entry that is greater than us */ + break; } else if (kim_comparison_is_equal_to (identity_comparison)) { /* already in list */ @@ -396,74 +415,14 @@ static kim_error kim_preferences_read (kim_preferences in_preferences) if (!err && !in_preferences) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { - kim_lifetime lifetime = kim_default_lifetime; - - err = kim_os_preferences_get_lifetime_for_key (kim_preference_key_lifetime, - kim_default_lifetime, - &lifetime); - - if (!err) { - err = kim_options_set_lifetime (in_preferences->options, lifetime); - } - } - - if (!err) { - kim_boolean renewable = kim_default_renewable; - - err = kim_os_preferences_get_boolean_for_key (kim_preference_key_renewable, - kim_default_renewable, - &renewable); - - if (!err) { - err = kim_options_set_renewable (in_preferences->options, renewable); - } - } - - if (!err) { - kim_lifetime renewal_lifetime = kim_default_renewal_lifetime; - - err = kim_os_preferences_get_lifetime_for_key (kim_preference_key_renewal_lifetime, - kim_default_renewal_lifetime, - &renewal_lifetime); - - if (!err) { - err = kim_options_set_renewal_lifetime (in_preferences->options, renewal_lifetime); - } - } - - if (!err) { - kim_boolean forwardable = kim_default_forwardable; - - err = kim_os_preferences_get_boolean_for_key (kim_preference_key_forwardable, - kim_default_forwardable, - &forwardable); - - if (!err) { - err = kim_options_set_forwardable (in_preferences->options, forwardable); - } - } - - if (!err) { - kim_boolean proxiable = kim_default_proxiable; - - err = kim_os_preferences_get_boolean_for_key (kim_preference_key_proxiable, - kim_default_proxiable, - &proxiable); - - if (!err) { - err = kim_options_set_proxiable (in_preferences->options, proxiable); - } - } - - if (!err) { - kim_boolean addressless = kim_default_addressless; + kim_options options = NULL; - err = kim_os_preferences_get_boolean_for_key (kim_preference_key_addressless, - kim_default_addressless, - &addressless); + err = kim_os_preferences_get_options_for_key (kim_preference_key_options, + &options); if (!err) { - err = kim_options_set_addressless (in_preferences->options, addressless); + kim_options_free (&in_preferences->options); + in_preferences->options = options; } } @@ -545,69 +504,8 @@ static kim_error kim_preferences_write (kim_preferences in_preferences) if (!err && !in_preferences) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && in_preferences->remember_options && in_preferences->options_changed) { - kim_lifetime lifetime = kim_default_lifetime; - - err = kim_options_get_lifetime (in_preferences->options, &lifetime); - - if (!err) { - err = kim_os_preferences_set_lifetime_for_key (kim_preference_key_lifetime, - lifetime); - } - - if (!err) { - kim_boolean renewable = kim_default_renewable; - - err = kim_options_get_renewable (in_preferences->options, &renewable); - - if (!err) { - err = kim_os_preferences_set_boolean_for_key (kim_preference_key_renewable, - renewable); - } - } - - if (!err) { - kim_lifetime renewal_lifetime = kim_default_renewal_lifetime; - - err = kim_options_get_renewal_lifetime (in_preferences->options, &renewal_lifetime); - - if (!err) { - err = kim_os_preferences_set_lifetime_for_key (kim_preference_key_renewal_lifetime, - renewal_lifetime); - } - } - - if (!err) { - kim_boolean forwardable = kim_default_forwardable; - - err = kim_options_get_forwardable (in_preferences->options, &forwardable); - - if (!err) { - err = kim_os_preferences_set_boolean_for_key (kim_preference_key_forwardable, - forwardable); - } - } - - if (!err) { - kim_boolean proxiable = kim_default_proxiable; - - err = kim_options_get_proxiable (in_preferences->options, &proxiable); - - if (!err) { - err = kim_os_preferences_set_boolean_for_key (kim_preference_key_proxiable, - proxiable); - } - } - - if (!err) { - kim_boolean addressless = kim_default_addressless; - - err = kim_options_get_addressless (in_preferences->options, &addressless); - - if (!err) { - err = kim_os_preferences_set_boolean_for_key (kim_preference_key_addressless, - addressless); - } - } + err = kim_os_preferences_set_options_for_key (kim_preference_key_options, + in_preferences->options); } if (!err && in_preferences->remember_options_changed) { @@ -709,10 +607,6 @@ kim_error kim_preferences_create (kim_preferences *out_preferences) err = kim_preferences_allocate (&preferences); } - if (!err) { - err = kim_options_create_from_defaults (&preferences->options); - } - if (!err) { err = kim_preferences_read (preferences); } diff --git a/src/kim/lib/kim_preferences_private.h b/src/kim/lib/kim_preferences_private.h index 831fba452..239098829 100644 --- a/src/kim/lib/kim_preferences_private.h +++ b/src/kim/lib/kim_preferences_private.h @@ -32,6 +32,7 @@ typedef struct kim_favorites_opaque *kim_favorites; typedef enum kim_preference_key_enum { + kim_preference_key_options, kim_preference_key_lifetime, kim_preference_key_renewable, kim_preference_key_renewal_lifetime, @@ -89,6 +90,12 @@ kim_error kim_favorites_remove_all_identities (kim_favorites io_favorites); /* OS-specific functions to be implemented per-platform */ +kim_error kim_os_preferences_get_options_for_key (kim_preference_key in_key, + kim_options *out_options); + +kim_error kim_os_preferences_set_options_for_key (kim_preference_key in_key, + kim_options in_options); + kim_error kim_os_preferences_get_identity_for_key (kim_preference_key in_key, kim_identity in_hardcoded_default, kim_identity *out_identity); @@ -102,13 +109,6 @@ kim_error kim_os_preferences_get_favorites_for_key (kim_preference_key in_key, kim_error kim_os_preferences_set_favorites_for_key (kim_preference_key in_key, kim_favorites in_favorites); -kim_error kim_os_preferences_get_time_for_key (kim_preference_key in_key, - kim_time in_hardcoded_default, - kim_time *out_time); - -kim_error kim_os_preferences_set_time_for_key (kim_preference_key in_key, - kim_time in_time); - kim_error kim_os_preferences_get_lifetime_for_key (kim_preference_key in_key, kim_lifetime in_hardcoded_default, kim_lifetime *out_lifetime); diff --git a/src/kim/lib/mac/kim_os_preferences.c b/src/kim/lib/mac/kim_os_preferences.c index fac8cf644..a915046a3 100644 --- a/src/kim/lib/mac/kim_os_preferences.c +++ b/src/kim/lib/mac/kim_os_preferences.c @@ -33,108 +33,132 @@ #define kim_os_preference_any_identity "KIM_IDENTITY_ANY" +#pragma mark - + /* ------------------------------------------------------------------------ */ -static kim_error kim_os_preferences_cfstring_for_key (kim_preference_key in_key, - CFStringRef *out_kim_string_key, - CFStringRef *out_kll_string_key) +static CFStringRef kim_os_preferences_cfstring_for_key (kim_preference_key in_key) { - kim_error err = KIM_NO_ERROR; - - if (!err && !out_kim_string_key) { err = check_error (KIM_NULL_PARAMETER_ERR); } - if (!err && !out_kll_string_key) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (in_key == kim_preference_key_options) { + return CFSTR ("CredentialOptions"); + + } else if (in_key == kim_preference_key_lifetime) { + return CFSTR ("CredentialLifetime"); + + } else if (in_key == kim_preference_key_renewable) { + return CFSTR ("RenewableCredentials"); + + } else if (in_key == kim_preference_key_renewal_lifetime) { + return CFSTR ("CredentialRenewalLifetime"); + + } else if (in_key == kim_preference_key_forwardable) { + return CFSTR ("ForwardableCredentials"); + + } else if (in_key == kim_preference_key_proxiable) { + return CFSTR ("ProxiableCredentials"); + + } else if (in_key == kim_preference_key_addressless) { + return CFSTR ("AddresslessCredentials"); + + } else if (in_key == kim_preference_key_remember_options) { + return CFSTR ("RememberCredentialAttributes"); + + } else if (in_key == kim_preference_key_client_identity) { + return CFSTR ("ClientIdentity"); + + } else if (in_key == kim_preference_key_remember_client_identity) { + return CFSTR ("RememberClientIdentity"); + + } else if (in_key == kim_preference_key_favorites) { + return CFSTR ("FavoriteIdentities"); + + } else if (in_key == kim_preference_key_minimum_lifetime) { + return CFSTR ("MinimumLifetime"); + + } else if (in_key == kim_preference_key_maximum_lifetime) { + return CFSTR ("MaximumLifetime"); + + } else if (in_key == kim_preference_key_minimum_renewal_lifetime) { + return CFSTR ("MinimumRenewalLifetime"); + + } else if (in_key == kim_preference_key_maximum_renewal_lifetime) { + return CFSTR ("MaximumRenewalLifetime"); + + } - if (!err) { - if (in_key == kim_preference_key_lifetime) { - *out_kim_string_key = CFSTR ("CredentialLifetime"); - *out_kll_string_key = CFSTR ("KLDefaultTicketLifetime"); - - } else if (in_key == kim_preference_key_renewable) { - *out_kim_string_key = CFSTR ("RenewableCredentials"); - *out_kll_string_key = CFSTR ("KLGetRenewableTickets"); - - } else if (in_key == kim_preference_key_renewal_lifetime) { - *out_kim_string_key = CFSTR ("CredentialRenewalLifetime"); - *out_kll_string_key = CFSTR ("KLDefaultRenewableLifetime"); - - } else if (in_key == kim_preference_key_forwardable) { - *out_kim_string_key = CFSTR ("ForwardableCredentials"); - *out_kll_string_key = CFSTR ("KLDefaultForwardableTicket"); - - } else if (in_key == kim_preference_key_proxiable) { - *out_kim_string_key = CFSTR ("ProxiableCredentials"); - *out_kll_string_key = CFSTR ("KLGetProxiableTickets"); - - } else if (in_key == kim_preference_key_addressless) { - *out_kim_string_key = CFSTR ("AddresslessCredentials"); - *out_kll_string_key = CFSTR ("KLGetAddresslessTickets"); - - } else if (in_key == kim_preference_key_remember_options) { - *out_kim_string_key = CFSTR ("RememberCredentialAttributes"); - *out_kll_string_key = CFSTR ("KLRememberExtras"); - - } else if (in_key == kim_preference_key_client_identity) { - *out_kim_string_key = CFSTR ("ClientIdentity"); - *out_kll_string_key = CFSTR ("KLName"); - - } else if (in_key == kim_preference_key_remember_client_identity) { - *out_kim_string_key = CFSTR ("RememberClientIdentity"); - *out_kll_string_key = CFSTR ("KLRememberPrincipal"); - - } else if (in_key == kim_preference_key_favorites) { - *out_kim_string_key = CFSTR ("FavoriteIdentities"); - *out_kll_string_key = CFSTR ("KLFavoriteIdentities"); - - } else if (in_key == kim_preference_key_minimum_lifetime) { - *out_kim_string_key = CFSTR ("MinimumLifetime"); - *out_kll_string_key = CFSTR ("KLMinimumTicketLifetime"); - - } else if (in_key == kim_preference_key_maximum_lifetime) { - *out_kim_string_key = CFSTR ("MaximumLifetime"); - *out_kll_string_key = CFSTR ("KLMaximumTicketLifetime"); - - } else if (in_key == kim_preference_key_minimum_renewal_lifetime) { - *out_kim_string_key = CFSTR ("MinimumRenewalLifetime"); - *out_kll_string_key = CFSTR ("KLMinimumRenewableLifetime"); - - } else if (in_key == kim_preference_key_maximum_renewal_lifetime) { - *out_kim_string_key = CFSTR ("MaximumRenewalLifetime"); - *out_kll_string_key = CFSTR ("KLMaximumRenewableLifetime"); - - } else { - /* ignore unsupported keys */ - kim_debug_printf ("Unsupported preference key %d", in_key); - *out_kim_string_key = NULL; - *out_kll_string_key = NULL; - } + return NULL; /* ignore unsupported keys */ +} + +/* ------------------------------------------------------------------------ */ + +static CFStringRef kim_os_preferences_compat_cfstring_for_key (kim_preference_key in_key) +{ + if (in_key == kim_preference_key_lifetime) { + return CFSTR ("KLDefaultTicketLifetime"); + + } else if (in_key == kim_preference_key_renewable) { + return CFSTR ("KLGetRenewableTickets"); + + } else if (in_key == kim_preference_key_renewal_lifetime) { + return CFSTR ("KLDefaultRenewableLifetime"); + + } else if (in_key == kim_preference_key_forwardable) { + return CFSTR ("KLDefaultForwardableTicket"); + + } else if (in_key == kim_preference_key_proxiable) { + return CFSTR ("KLGetProxiableTickets"); + + } else if (in_key == kim_preference_key_addressless) { + return CFSTR ("KLGetAddresslessTickets"); + + } else if (in_key == kim_preference_key_remember_options) { + return CFSTR ("KLRememberExtras"); + + } else if (in_key == kim_preference_key_client_identity) { + return CFSTR ("KLName"); + + } else if (in_key == kim_preference_key_remember_client_identity) { + return CFSTR ("KLRememberPrincipal"); + + } else if (in_key == kim_preference_key_favorites) { + return CFSTR ("KLFavoriteIdentities"); + + } else if (in_key == kim_preference_key_minimum_lifetime) { + return CFSTR ("KLMinimumTicketLifetime"); + + } else if (in_key == kim_preference_key_maximum_lifetime) { + return CFSTR ("KLMaximumTicketLifetime"); + + } else if (in_key == kim_preference_key_minimum_renewal_lifetime) { + return CFSTR ("KLMinimumRenewableLifetime"); + + } else if (in_key == kim_preference_key_maximum_renewal_lifetime) { + return CFSTR ("KLMaximumRenewableLifetime"); + } - return check_error (err); + return NULL; /* ignore unsupported keys */ } /* ------------------------------------------------------------------------ */ -static kim_error kim_os_preferences_get_value (kim_preference_key in_key, - CFTypeID in_type, - CFPropertyListRef *out_value) +static kim_error kim_os_preferences_copy_value_for_file (CFStringRef in_key, + CFTypeID in_type, + CFStringRef in_file, + CFPropertyListRef *out_value) { kim_error err = KIM_NO_ERROR; CFPropertyListRef value = NULL; CFStringRef users[] = { kCFPreferencesCurrentUser, kCFPreferencesAnyUser, NULL }; - CFStringRef files[] = { KIM_PREFERENCES_FILE, KLL_PREFERENCES_FILE, NULL }; CFStringRef hosts[] = { kCFPreferencesCurrentHost, kCFPreferencesAnyHost, NULL }; - CFStringRef keys[] = { NULL, NULL, NULL }; + if (!err && !in_key ) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !in_file ) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && !out_value) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { - /* Index must correspond to the appropriate file */ - err = kim_os_preferences_cfstring_for_key (in_key, &keys[0], &keys[1]); - } - - if (!err) { - kim_count u, f, h; + kim_count u, h; if (!kim_library_allow_home_directory_access()) { users[0] = kCFPreferencesAnyUser; @@ -142,10 +166,8 @@ static kim_error kim_os_preferences_get_value (kim_preference_key in_key, } for (u = 0; !value && users[u]; u++) { - for (f = 0; !value && files[f] && keys[f]; f++) { - for (h = 0; !value && hosts[h]; h++) { - value = CFPreferencesCopyValue (keys[f], files[f], users[u], hosts[h]); - } + for (h = 0; !value && hosts[h]; h++) { + value = CFPreferencesCopyValue (in_key, in_file, users[u], hosts[h]); } } @@ -165,27 +187,60 @@ static kim_error kim_os_preferences_get_value (kim_preference_key in_key, return check_error (err); } +#pragma mark - + +/* ------------------------------------------------------------------------ */ + +static kim_error kim_os_preferences_copy_value (kim_preference_key in_key, + CFTypeID in_type, + CFPropertyListRef *out_value) +{ + kim_error err = KIM_NO_ERROR; + CFStringRef key = kim_os_preferences_cfstring_for_key (in_key); + + err = kim_os_preferences_copy_value_for_file (key, in_type, + KIM_PREFERENCES_FILE, + out_value); + + return check_error (err); +} + +/* ------------------------------------------------------------------------ */ + +static kim_error kim_os_preferences_copy_value_compat (kim_preference_key in_key, + CFTypeID in_type, + CFPropertyListRef *out_value) +{ + kim_error err = KIM_NO_ERROR; + CFStringRef key = kim_os_preferences_compat_cfstring_for_key (in_key); + + err = kim_os_preferences_copy_value_for_file (key, in_type, + KLL_PREFERENCES_FILE, + out_value); + + return check_error (err); +} + /* ------------------------------------------------------------------------ */ static kim_error kim_os_preferences_set_value (kim_preference_key in_key, - CFPropertyListRef in_value) + CFPropertyListRef in_value) { kim_error err = KIM_NO_ERROR; - CFStringRef kim_key = NULL; - CFStringRef kll_key = NULL; + CFStringRef key = NULL; if (!err && !in_value) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { - err = kim_os_preferences_cfstring_for_key (in_key, &kim_key, &kll_key); + key = kim_os_preferences_cfstring_for_key (in_key); } - if (!err && kim_key) { + if (!err && key) { kim_boolean homedir_ok = kim_library_allow_home_directory_access(); CFStringRef user = homedir_ok ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser; CFStringRef host = homedir_ok ? kCFPreferencesAnyHost : kCFPreferencesCurrentHost; - CFPreferencesSetValue (kim_key, in_value, KIM_PREFERENCES_FILE, user, host); + CFPreferencesSetValue (key, in_value, KIM_PREFERENCES_FILE, user, host); if (!CFPreferencesSynchronize (KIM_PREFERENCES_FILE, user, host)) { err = check_error (KIM_PREFERENCES_WRITE_ERR); } @@ -209,8 +264,14 @@ kim_error kim_os_preferences_get_identity_for_key (kim_preference_key in_key, if (!err && !out_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { - err = kim_os_preferences_get_value (in_key, CFStringGetTypeID (), - (CFPropertyListRef *) &value); + err = kim_os_preferences_copy_value (in_key, CFStringGetTypeID (), + (CFPropertyListRef *) &value); + + } + + if (!err && !value) { + err = kim_os_preferences_copy_value_compat (in_key, CFStringGetTypeID (), + (CFPropertyListRef *) &value); } if (!err) { @@ -272,117 +333,57 @@ kim_error kim_os_preferences_set_identity_for_key (kim_preference_key in_key, /* ------------------------------------------------------------------------ */ -kim_error kim_os_preferences_get_favorites_for_key (kim_preference_key in_key, - kim_favorites io_favorites) +kim_error kim_os_preferences_get_lifetime_for_key (kim_preference_key in_key, + kim_lifetime in_hardcoded_default, + kim_lifetime *out_lifetime) { kim_error err = KIM_NO_ERROR; - CFArrayRef value = NULL; + CFNumberRef value = NULL; - if (!err && !io_favorites) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !out_lifetime) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { - err = kim_os_preferences_get_value (in_key, CFArrayGetTypeID (), - (CFPropertyListRef *) &value); + err = kim_os_preferences_copy_value (in_key, CFNumberGetTypeID (), + (CFPropertyListRef *) &value); + } + + if (!err && !value) { + err = kim_os_preferences_copy_value_compat (in_key, CFNumberGetTypeID (), + (CFPropertyListRef *) &value); } if (!err) { - if (!value || CFArrayGetCount (value) < 1) { - err = kim_favorites_remove_all_identities (io_favorites); - - } else { - CFIndex count = CFArrayGetCount (value); - CFIndex i; - - for (i = 0; !err && i < count; i++) { - CFStringRef cfstring = NULL; - kim_string string = NULL; - kim_identity identity = NULL; - - cfstring = (CFStringRef) CFArrayGetValueAtIndex (value, i); - if (!cfstring || CFGetTypeID (cfstring) != CFStringGetTypeID ()) { - err = check_error (KIM_PREFERENCES_READ_ERR); - } - - if (!err) { - err = kim_os_string_create_from_cfstring (&string, cfstring); - } - - if (!err) { - err = kim_identity_create_from_string (&identity, string); - } - - if (!err) { - err = kim_favorites_add_identity (io_favorites, identity, - KIM_OPTIONS_DEFAULT); - } - - kim_identity_free (&identity); - kim_string_free (&string); + if (value) { + SInt32 number; // CFNumbers are signed so we need to cast + if (CFNumberGetValue (value, kCFNumberSInt32Type, &number) != TRUE) { + err = KIM_OUT_OF_MEMORY_ERR; + } else { + *out_lifetime = number; } + } else { + *out_lifetime = in_hardcoded_default; } } - if (err) { - kim_favorites_remove_all_identities (io_favorites); - } - if (value) { CFRelease (value); } return check_error (err); } /* ------------------------------------------------------------------------ */ -kim_error kim_os_preferences_set_favorites_for_key (kim_preference_key in_key, - kim_favorites in_favorites) + +kim_error kim_os_preferences_set_lifetime_for_key (kim_preference_key in_key, + kim_lifetime in_lifetime) { kim_error err = KIM_NO_ERROR; - kim_count count = 0; - CFMutableArrayRef value = NULL; - - if (!err && !in_favorites) { err = check_error (KIM_NULL_PARAMETER_ERR); } - - if (!err) { - err = kim_favorites_get_number_of_identities (in_favorites, &count); - } + CFNumberRef value = NULL; + SInt32 number = (SInt32) in_lifetime; if (!err) { - value = CFArrayCreateMutable (kCFAllocatorDefault, count, - &kCFTypeArrayCallBacks); + value = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &number); if (!value) { err = KIM_OUT_OF_MEMORY_ERR; } } - if (!err) { - kim_count i; - - for (i = 0; !err && i < count; i++) { - kim_identity identity = NULL; - kim_options options = NULL; - kim_string string = NULL; - CFStringRef cfstring = NULL; - - err = kim_favorites_get_identity_at_index (in_favorites, i, - &identity, - &options); - - if (!err) { - err = kim_identity_get_string (identity, &string); - } - - if (!err) { - err = kim_os_string_get_cfstring (string, &cfstring); - } - - if (!err) { - CFArrayAppendValue (value, cfstring); - } - - if (cfstring) { CFRelease (cfstring); } - kim_string_free (&string); - kim_options_free (&options); - kim_identity_free (&identity); - } - } - if (!err) { err = kim_os_preferences_set_value (in_key, value); } @@ -394,30 +395,30 @@ kim_error kim_os_preferences_set_favorites_for_key (kim_preference_key in_key, /* ------------------------------------------------------------------------ */ -kim_error kim_os_preferences_get_time_for_key (kim_preference_key in_key, - kim_time in_hardcoded_default, - kim_time *out_time) +kim_error kim_os_preferences_get_boolean_for_key (kim_preference_key in_key, + kim_boolean in_hardcoded_default, + kim_boolean *out_boolean) { kim_error err = KIM_NO_ERROR; - CFNumberRef value = NULL; + CFBooleanRef value = NULL; - if (!err && !out_time) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !out_boolean) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { - err = kim_os_preferences_get_value (in_key, CFNumberGetTypeID (), - (CFPropertyListRef *) &value); + err = kim_os_preferences_copy_value (in_key, CFBooleanGetTypeID (), + (CFPropertyListRef *) &value); + } + + if (!err && !value) { + err = kim_os_preferences_copy_value_compat (in_key, CFBooleanGetTypeID (), + (CFPropertyListRef *) &value); } if (!err) { if (value) { - SInt32 number; // CFNumbers are signed so we need to cast - if (CFNumberGetValue (value, kCFNumberSInt32Type, &number) != TRUE) { - err = KIM_OUT_OF_MEMORY_ERR; - } else { - *out_time = number; - } + *out_boolean = CFBooleanGetValue (value); } else { - *out_time = in_hardcoded_default; + *out_boolean = in_hardcoded_default; } } @@ -428,126 +429,647 @@ kim_error kim_os_preferences_get_time_for_key (kim_preference_key in_key, /* ------------------------------------------------------------------------ */ -kim_error kim_os_preferences_set_time_for_key (kim_preference_key in_key, - kim_time in_time) +kim_error kim_os_preferences_set_boolean_for_key (kim_preference_key in_key, + kim_boolean in_boolean) { kim_error err = KIM_NO_ERROR; - CFNumberRef value = NULL; - SInt32 number = (SInt32) in_time; - - if (!err) { - value = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &number); - if (!value) { err = KIM_OUT_OF_MEMORY_ERR; } - } + CFBooleanRef value = in_boolean ? kCFBooleanTrue : kCFBooleanFalse; if (!err) { err = kim_os_preferences_set_value (in_key, value); } - if (value) { CFRelease (value); } - return check_error (err); } +#pragma mark - + /* ------------------------------------------------------------------------ */ -kim_error kim_os_preferences_get_lifetime_for_key (kim_preference_key in_key, - kim_lifetime in_hardcoded_default, - kim_lifetime *out_lifetime) +static kim_error kim_os_preferences_copy_value_for_dict_key (CFDictionaryRef in_dictionary, + kim_preference_key in_key, + CFTypeID in_type, + CFPropertyListRef *out_value) { kim_error err = KIM_NO_ERROR; - CFNumberRef value = NULL; + CFPropertyListRef value = NULL; - if (!err && !out_lifetime) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !in_dictionary) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !out_value ) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { - err = kim_os_preferences_get_value (in_key, CFNumberGetTypeID (), - (CFPropertyListRef *) &value); + CFStringRef key = kim_os_preferences_cfstring_for_key (in_key); + + value = CFDictionaryGetValue (in_dictionary, key); + if (value && CFGetTypeID (value) != in_type) { + err = check_error (KIM_PREFERENCES_READ_ERR); + } } if (!err) { - if (value) { - SInt32 number; // CFNumbers are signed so we need to cast - if (CFNumberGetValue (value, kCFNumberSInt32Type, &number) != TRUE) { - err = KIM_OUT_OF_MEMORY_ERR; - } else { - *out_lifetime = number; - } - } else { - *out_lifetime = in_hardcoded_default; - } + *out_value = value; } - if (value) { CFRelease (value); } - return check_error (err); } /* ------------------------------------------------------------------------ */ -kim_error kim_os_preferences_set_lifetime_for_key (kim_preference_key in_key, - kim_lifetime in_lifetime) +static kim_error kim_os_preferences_set_value_for_dict_key (CFMutableDictionaryRef in_dictionary, + kim_preference_key in_key, + CFPropertyListRef in_value) { kim_error err = KIM_NO_ERROR; - CFNumberRef value = NULL; - SInt32 number = (SInt32) in_lifetime; - if (!err) { - value = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &number); - if (!value) { err = KIM_OUT_OF_MEMORY_ERR; } - } + if (!err && !in_dictionary) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !in_value ) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { - err = kim_os_preferences_set_value (in_key, value); + CFStringRef key = kim_os_preferences_cfstring_for_key (in_key); + + CFDictionarySetValue (in_dictionary, key, in_value); } - if (value) { CFRelease (value); } - return check_error (err); } /* ------------------------------------------------------------------------ */ -kim_error kim_os_preferences_get_boolean_for_key (kim_preference_key in_key, - kim_boolean in_hardcoded_default, - kim_boolean *out_boolean) +static kim_error kim_os_preferences_dictionary_to_options (CFDictionaryRef in_dictionary, + kim_options *out_options) { kim_error err = KIM_NO_ERROR; - CFBooleanRef value = NULL; + kim_options options = KIM_OPTIONS_DEFAULT; + kim_boolean found_options = 0; - if (!err && !out_boolean) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !in_dictionary) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !out_options ) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { - err = kim_os_preferences_get_value (in_key, CFBooleanGetTypeID (), - (CFPropertyListRef *) &value); + err = kim_options_create_empty (&options); } if (!err) { - if (value) { - *out_boolean = CFBooleanGetValue (value); - } else { - *out_boolean = in_hardcoded_default; + CFBooleanRef value = NULL; + + err = kim_os_preferences_copy_value_for_dict_key (in_dictionary, + kim_preference_key_renewable, + CFBooleanGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value) { + found_options = 1; + err = kim_options_set_renewable (options, CFBooleanGetValue (value)); } } - if (value) { CFRelease (value); } + if (!err) { + CFNumberRef value = NULL; + SInt32 lifetime; // CFNumbers are signed so we need to cast + + err = kim_os_preferences_copy_value_for_dict_key (in_dictionary, + kim_preference_key_lifetime, + CFNumberGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value && CFNumberGetValue (value, kCFNumberSInt32Type, + &lifetime)) { + found_options = 1; + err = kim_options_set_lifetime (options, lifetime); + } + } - return check_error (err); -} + if (!err) { + CFNumberRef value = NULL; + SInt32 lifetime; // CFNumbers are signed so we need to cast + + err = kim_os_preferences_copy_value_for_dict_key (in_dictionary, + kim_preference_key_renewal_lifetime, + CFNumberGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value && CFNumberGetValue (value, kCFNumberSInt32Type, + &lifetime)) { + found_options = 1; + err = kim_options_set_renewal_lifetime (options, lifetime); + } } + + if (!err) { + CFBooleanRef value = NULL; + + err = kim_os_preferences_copy_value_for_dict_key (in_dictionary, + kim_preference_key_forwardable, + CFBooleanGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value) { + found_options = 1; + err = kim_options_set_forwardable (options, CFBooleanGetValue (value)); + } + } + + if (!err) { + CFBooleanRef value = NULL; + + err = kim_os_preferences_copy_value_for_dict_key (in_dictionary, + kim_preference_key_proxiable, + CFBooleanGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value) { + found_options = 1; + err = kim_options_set_proxiable (options, CFBooleanGetValue (value)); + } + } + + if (!err) { + CFBooleanRef value = NULL; + + err = kim_os_preferences_copy_value_for_dict_key (in_dictionary, + kim_preference_key_addressless, + CFBooleanGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value) { + found_options = 1; + err = kim_options_set_addressless (options, CFBooleanGetValue (value)); + } + } + + if (!err && !found_options) { + kim_options_free (&options); + options = KIM_OPTIONS_DEFAULT; + } + + if (!err) { + *out_options = options; + options = NULL; + } + + kim_options_free (&options); + + return check_error (err); +} /* ------------------------------------------------------------------------ */ -kim_error kim_os_preferences_set_boolean_for_key (kim_preference_key in_key, - kim_boolean in_boolean) +static kim_error kim_os_preferences_options_to_dictionary (kim_options in_options, + CFMutableDictionaryRef io_dictionary) { kim_error err = KIM_NO_ERROR; - CFBooleanRef value = in_boolean ? kCFBooleanTrue : kCFBooleanFalse; + + if (!err && !in_options ) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !io_dictionary) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { - err = kim_os_preferences_set_value (in_key, value); + CFNumberRef value = NULL; + kim_lifetime lifetime; + + err = kim_options_get_lifetime (in_options, &lifetime); + + if (!err) { + SInt32 number = (SInt32) lifetime; + + value = CFNumberCreate (kCFAllocatorDefault, + kCFNumberSInt32Type, &number); + if (!value) { err = KIM_OUT_OF_MEMORY_ERR; } + } + + if (!err) { + err = kim_os_preferences_set_value_for_dict_key (io_dictionary, + kim_preference_key_lifetime, + value); + } + + if (value) { CFRelease (value); } + } + + if (!err) { + kim_boolean boolean; + + err = kim_options_get_renewable (in_options, &boolean); + + if (!err) { + CFBooleanRef value = boolean ? kCFBooleanTrue : kCFBooleanFalse; + + err = kim_os_preferences_set_value_for_dict_key (io_dictionary, + kim_preference_key_renewable, + value); + } + } + + if (!err) { + CFNumberRef value = NULL; + kim_lifetime lifetime; + + err = kim_options_get_renewal_lifetime (in_options, &lifetime); + + if (!err) { + SInt32 number = (SInt32) lifetime; + + value = CFNumberCreate (kCFAllocatorDefault, + kCFNumberSInt32Type, &number); + if (!value) { err = KIM_OUT_OF_MEMORY_ERR; } + } + + if (!err) { + err = kim_os_preferences_set_value_for_dict_key (io_dictionary, + kim_preference_key_renewal_lifetime, + value); + } + + if (value) { CFRelease (value); } + } + + if (!err) { + kim_boolean boolean; + + err = kim_options_get_forwardable (in_options, &boolean); + + if (!err) { + CFBooleanRef value = boolean ? kCFBooleanTrue : kCFBooleanFalse; + + err = kim_os_preferences_set_value_for_dict_key (io_dictionary, + kim_preference_key_forwardable, + value); + } + } + + if (!err) { + kim_boolean boolean; + + err = kim_options_get_proxiable (in_options, &boolean); + + if (!err) { + CFBooleanRef value = boolean ? kCFBooleanTrue : kCFBooleanFalse; + + err = kim_os_preferences_set_value_for_dict_key (io_dictionary, + kim_preference_key_proxiable, + value); + } + } + + if (!err) { + kim_boolean boolean; + + err = kim_options_get_addressless (in_options, &boolean); + + if (!err) { + CFBooleanRef value = boolean ? kCFBooleanTrue : kCFBooleanFalse; + + err = kim_os_preferences_set_value_for_dict_key (io_dictionary, + kim_preference_key_addressless, + value); + } + } + + return check_error (err); +} + + + +#pragma mark - + +/* ------------------------------------------------------------------------ */ + +static kim_error kim_os_preferences_get_options_compat (kim_options *out_options) +{ + kim_error err = KIM_NO_ERROR; + kim_options options = KIM_OPTIONS_DEFAULT; + kim_boolean found_options = 0; + + if (!err && !out_options) { err = check_error (KIM_NULL_PARAMETER_ERR); } + + if (!err) { + err = kim_options_create_empty (&options); + } + + if (!err) { + CFNumberRef value = NULL; + SInt32 lifetime; // CFNumbers are signed so we need to cast + + err = kim_os_preferences_copy_value_compat (kim_preference_key_lifetime, + CFNumberGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value && CFNumberGetValue (value, kCFNumberSInt32Type, + &lifetime)) { + found_options = 1; + err = kim_options_set_lifetime (options, lifetime); + } + + if (value) { CFRelease (value); } + } + + if (!err) { + CFBooleanRef value = NULL; + + err = kim_os_preferences_copy_value_compat (kim_preference_key_renewable, + CFBooleanGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value) { + found_options = 1; + err = kim_options_set_renewable (options, CFBooleanGetValue (value)); + } + + if (value) { CFRelease (value); } + } + + if (!err) { + CFNumberRef value = NULL; + SInt32 lifetime; // CFNumbers are signed so we need to cast + + err = kim_os_preferences_copy_value_compat (kim_preference_key_renewal_lifetime, + CFNumberGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value && CFNumberGetValue (value, kCFNumberSInt32Type, + &lifetime)) { + found_options = 1; + err = kim_options_set_renewal_lifetime (options, lifetime); + } + + if (value) { CFRelease (value); } + } + + if (!err) { + CFBooleanRef value = NULL; + + err = kim_os_preferences_copy_value_compat (kim_preference_key_forwardable, + CFBooleanGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value) { + found_options = 1; + err = kim_options_set_forwardable (options, CFBooleanGetValue (value)); + } + + if (value) { CFRelease (value); } + } + + if (!err) { + CFBooleanRef value = NULL; + + err = kim_os_preferences_copy_value_compat (kim_preference_key_proxiable, + CFBooleanGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value) { + found_options = 1; + err = kim_options_set_proxiable (options, CFBooleanGetValue (value)); + } + + if (value) { CFRelease (value); } + } + + if (!err) { + CFBooleanRef value = NULL; + + err = kim_os_preferences_copy_value_compat (kim_preference_key_addressless, + CFBooleanGetTypeID (), + (CFPropertyListRef *) &value); + + if (!err && value) { + found_options = 1; + err = kim_options_set_addressless (options, CFBooleanGetValue (value)); + } + + if (value) { CFRelease (value); } + } + + if (!err && !found_options) { + kim_options_free (&options); + options = KIM_OPTIONS_DEFAULT; + } + + if (!err) { + *out_options = options; + } + + return check_error (err); +} + +/* ------------------------------------------------------------------------ */ + +kim_error kim_os_preferences_get_options_for_key (kim_preference_key in_key, + kim_options *out_options) +{ + kim_error err = KIM_NO_ERROR; + CFDictionaryRef dictionary = NULL; + kim_options options = KIM_OPTIONS_DEFAULT; + + if (!err && !out_options) { err = check_error (KIM_NULL_PARAMETER_ERR); } + + if (!err) { + err = kim_os_preferences_copy_value (in_key, CFDictionaryGetTypeID (), + (CFPropertyListRef *) &dictionary); + + if (!err && dictionary) { + err = kim_os_preferences_dictionary_to_options (dictionary, &options); + } + } + + if (!err && !dictionary) { + err = kim_os_preferences_get_options_compat (&options); + } + + if (!err) { + *out_options = options; + } + + if (dictionary) { CFRelease (dictionary); } + + return check_error (err); +} + +/* ------------------------------------------------------------------------ */ + +kim_error kim_os_preferences_set_options_for_key (kim_preference_key in_key, + kim_options in_options) +{ + kim_error err = KIM_NO_ERROR; + CFMutableDictionaryRef dictionary = NULL; + + if (!err && !in_options) { err = check_error (KIM_NULL_PARAMETER_ERR); } + + if (!err) { + dictionary = CFDictionaryCreateMutable (kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!dictionary) { err = check_error (KIM_OUT_OF_MEMORY_ERR); } + } + + if (!err) { + err = kim_os_preferences_options_to_dictionary (in_options, dictionary); + } + + if (!err) { + err = kim_os_preferences_set_value (in_key, dictionary); + } + + if (dictionary) { CFRelease (dictionary); } + + return check_error (err); +} + +#pragma mark - + +/* ------------------------------------------------------------------------ */ + +kim_error kim_os_preferences_get_favorites_for_key (kim_preference_key in_key, + kim_favorites io_favorites) +{ + kim_error err = KIM_NO_ERROR; + CFArrayRef value = NULL; + + if (!err && !io_favorites) { err = check_error (KIM_NULL_PARAMETER_ERR); } + + if (!err) { + err = kim_os_preferences_copy_value (in_key, CFArrayGetTypeID (), + (CFPropertyListRef *) &value); + } + + if (!err && value) { + if (!value || CFArrayGetCount (value) < 1) { + err = kim_favorites_remove_all_identities (io_favorites); + + } else { + CFIndex count = CFArrayGetCount (value); + CFIndex i; + + for (i = 0; !err && i < count; i++) { + CFDictionaryRef dictionary = NULL; + kim_options options = KIM_OPTIONS_DEFAULT; + CFStringRef cfstring = NULL; + + dictionary = (CFDictionaryRef) CFArrayGetValueAtIndex (value, i); + if (!dictionary || CFGetTypeID (dictionary) != CFDictionaryGetTypeID ()) { + err = check_error (KIM_PREFERENCES_READ_ERR); + } + + if (!err) { + err = kim_os_preferences_copy_value_for_dict_key (dictionary, + kim_preference_key_client_identity, + CFStringGetTypeID (), + (CFPropertyListRef *) &cfstring); + } + + if (!err && cfstring) { + kim_string string = NULL; + kim_identity identity = NULL; + + err = kim_os_string_create_from_cfstring (&string, cfstring); + + if (!err) { + err = kim_identity_create_from_string (&identity, string); + } + + if (!err && (CFDictionaryGetCount (dictionary) > 1)) { + err = kim_os_preferences_dictionary_to_options (dictionary, + &options); + } + + if (!err) { + err = kim_favorites_add_identity (io_favorites, identity, + options); + } + + kim_string_free (&string); + kim_options_free (&options); + kim_identity_free (&identity); + } + } + + if (err) { + kim_favorites_remove_all_identities (io_favorites); + } + } } + if (value) { CFRelease (value); } + return check_error (err); } /* ------------------------------------------------------------------------ */ +kim_error kim_os_preferences_set_favorites_for_key (kim_preference_key in_key, + kim_favorites in_favorites) +{ + kim_error err = KIM_NO_ERROR; + kim_count count = 0; + CFMutableArrayRef array = NULL; + + if (!err && !in_favorites) { err = check_error (KIM_NULL_PARAMETER_ERR); } + + if (!err) { + err = kim_favorites_get_number_of_identities (in_favorites, &count); + } + + if (!err) { + array = CFArrayCreateMutable (kCFAllocatorDefault, count, + &kCFTypeArrayCallBacks); + if (!array) { err = KIM_OUT_OF_MEMORY_ERR; } + } + + if (!err) { + kim_count i; + + for (i = 0; !err && i < count; i++) { + kim_identity identity = NULL; + kim_options options = NULL; + kim_string string = NULL; + CFStringRef cfstring = NULL; + CFMutableDictionaryRef dictionary = NULL; + + err = kim_favorites_get_identity_at_index (in_favorites, i, + &identity, + &options); + + if (!err) { + err = kim_identity_get_string (identity, &string); + } + + if (!err) { + err = kim_os_string_get_cfstring (string, &cfstring); + } + + if (!err) { + dictionary = CFDictionaryCreateMutable (kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!dictionary) { err = check_error (KIM_OUT_OF_MEMORY_ERR); } + } + + if (!err) { + err = kim_os_preferences_set_value_for_dict_key (dictionary, + kim_preference_key_client_identity, + cfstring); + } + + if (!err && options) { + err = kim_os_preferences_options_to_dictionary (options, + dictionary); + } + + if (!err) { + CFArrayAppendValue (array, dictionary); + } + + if (dictionary) { CFRelease (dictionary); } + if (cfstring ) { CFRelease (cfstring); } + kim_string_free (&string); + kim_options_free (&options); + kim_identity_free (&identity); + } + } + + if (!err) { + err = kim_os_preferences_set_value (in_key, array); + } + + if (array) { CFRelease (array); } + + return check_error (err); +} + diff --git a/src/kim/test/main.c b/src/kim/test/main.c index 03194bf1c..55846e7ae 100644 --- a/src/kim/test/main.c +++ b/src/kim/test/main.c @@ -68,5 +68,7 @@ int main (int argc, const char * argv[]) test_kim_selection_hints_remember_identity (state); + test_kim_preferences_add_favorite_identity (state); + return test_cleanup (state); } diff --git a/src/kim/test/test_kim_preferences.c b/src/kim/test/test_kim_preferences.c index 8ce61fe08..581191212 100644 --- a/src/kim/test/test_kim_preferences.c +++ b/src/kim/test/test_kim_preferences.c @@ -102,7 +102,7 @@ void test_kim_preferences_set_options (kim_test_state_t state) if (!err) { err = kim_options_set_lifetime (options, TEST_LIFETIME); - fail_if_error (state, "kim_options_set_data", err, + fail_if_error (state, "kim_options_set_lifetime", err, "while setting the lifetime to %d", TEST_LIFETIME); } @@ -385,3 +385,188 @@ void test_kim_preferences_set_client_identity (kim_test_state_t state) end_test (state); } + + +struct favorite_identity { + kim_string identity; + kim_lifetime lifetime; + kim_lifetime renewal_lifetime; +}; + +struct favorite_identity fids[] = { +{ "bob@EXAMPLE.COM", 7777, 8888 }, +{ "alice@UNIVERSITY.EDU", 12345, 54321 }, +{ "bob@COMPANY.COM", 5555, 6666 }, +{ "alice/admin@EXAMPLE.COM", 2222, 3333 }, +{ NULL, 0, 0 } +}; + +/* ------------------------------------------------------------------------ */ + +void test_kim_preferences_add_favorite_identity (kim_test_state_t state) +{ + kim_error err = KIM_NO_ERROR; + + start_test (state, "kim_preferences_add_favorite_identity"); + + if (!err) { + kim_preferences prefs = NULL; + kim_options options = NULL; + kim_count i; + + err = kim_preferences_create (&prefs); + fail_if_error (state, "kim_preferences_create", err, + "while creating preferences"); + + if (!err) { + err = kim_preferences_remove_all_favorite_identities (prefs); + fail_if_error (state, "kim_preferences_remove_all_favorite_identities", err, + "while removing all favorite identities"); + } + + if (!err) { + err = kim_options_create (&options); + fail_if_error (state, "kim_options_create", err, + "while creating options"); + } + + for (i = 0; !err && fids[i].identity; i++) { + kim_identity identity = NULL; + + err = kim_identity_create_from_string (&identity, fids[i].identity); + fail_if_error (state, "kim_identity_create_from_string", err, + "while creating the identity for %s", + fids[i].identity); + + if (!err) { + err = kim_options_set_lifetime (options, fids[i].lifetime); + fail_if_error (state, "kim_options_set_lifetime", err, + "while setting the lifetime to %d", + (int) fids[i].lifetime); + } + + if (!err) { + err = kim_options_set_renewal_lifetime (options, fids[i].renewal_lifetime); + fail_if_error (state, "kim_options_set_renewal_lifetime", err, + "while setting the renewal lifetime to %d", + (int) fids[i].renewal_lifetime); + } + + if (!err) { + err = kim_preferences_add_favorite_identity (prefs, identity, options); + fail_if_error (state, "kim_preferences_add_favorite_identity", err, + "while adding %s to the favorite identities", + fids[i].identity); + } + + kim_identity_free (&identity); + } + + if (!err) { + err = kim_preferences_synchronize (prefs); + fail_if_error (state, "kim_preferences_synchronize", err, + "while setting the favorite identities"); + } + + kim_options_free (&options); + kim_preferences_free (&prefs); + } + + if (!err) { + kim_preferences prefs = NULL; + kim_count count, i; + + err = kim_preferences_create (&prefs); + fail_if_error (state, "kim_preferences_create", err, + "while creating preferences"); + + if (!err) { + err = kim_preferences_get_number_of_favorite_identities (prefs, &count); + fail_if_error (state, "kim_preferences_get_number_of_favorite_identities", err, + "while getting number of favorite identities"); + } + + + for (i = 0; !err && fids[i].identity; i++) { + kim_identity identity = NULL; + kim_count j; + kim_boolean found = 0; + + err = kim_identity_create_from_string (&identity, fids[i].identity); + fail_if_error (state, "kim_identity_create_from_string", err, + "while creating the identity for %s", + fids[i].identity); + + for (j = 0; j < count; j++) { + kim_identity compare_identity = NULL; + kim_options compare_options = NULL; + kim_comparison comparison; + + err = kim_preferences_get_favorite_identity_at_index (prefs, j, + &compare_identity, + &compare_options); + fail_if_error (state, "kim_preferences_get_favorite_identity_at_index", err, + "while getting favorite identity %d", (int) j); + + if (!err) { + err = kim_identity_compare (identity, compare_identity, + &comparison); + fail_if_error (state, "kim_identity_compare", err, + "while comparing %s to favorite identity %d", + fids[i].identity, (int) i); + } + + if (!err && kim_comparison_is_equal_to (comparison)) { + kim_lifetime compare_lifetime; + kim_lifetime compare_renewal_lifetime; + + found = 1; + + err = kim_options_get_lifetime (compare_options, &compare_lifetime); + fail_if_error (state, "kim_options_get_lifetime", err, + "while getting the lifetime for %s", + fids[i].identity); + + if (!err && fids[i].lifetime != compare_lifetime) { + log_failure (state, "Unexpected lifetime for %s (got %d, expected %d)", + fids[i].identity, (int) compare_lifetime, + (int) fids[i].lifetime); + } + + if (!err) { + err = kim_options_get_renewal_lifetime (compare_options, + &compare_renewal_lifetime); + fail_if_error (state, "kim_options_get_renewal_lifetime", err, + "while getting the lifetime for %s", + fids[i].identity); + } + + if (!err && fids[i].renewal_lifetime != compare_renewal_lifetime) { + log_failure (state, "Unexpected renewal lifetime for %s (got %d, expected %d)", + fids[i].identity, + (int) compare_renewal_lifetime, + (int) fids[i].renewal_lifetime); + } + } + + kim_identity_free (&compare_identity); + kim_options_free (&compare_options); + } + + if (!err && !found) { + log_failure (state, "Favorite identity %s not found in favorite identities list", + fids[i].identity); + } + } + + if (!err && i != count) { + log_failure (state, "Unexpected number of favorite identities (got %d, expected %d)", + (int) count, (int) i); + } + + kim_preferences_free (&prefs); + } + + end_test (state); +} + diff --git a/src/kim/test/test_kim_preferences.h b/src/kim/test/test_kim_preferences.h index e86f11f2f..275b291a4 100644 --- a/src/kim/test/test_kim_preferences.h +++ b/src/kim/test/test_kim_preferences.h @@ -39,4 +39,6 @@ void test_kim_preferences_set_remember_options (kim_test_state_t state); void test_kim_preferences_set_client_identity (kim_test_state_t state); +void test_kim_preferences_add_favorite_identity (kim_test_state_t state); + #endif /* TEST_KIM_PREFERENCES_H */ -- 2.26.2