summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/kim/kim_credential.h1004
-rw-r--r--src/include/kim/kim_identity.h21
-rw-r--r--src/include/kim/kim_options.h147
-rw-r--r--src/include/kim/kim_ui_plugin.h55
-rw-r--r--src/kim/lib/kim-lite.exports12
-rw-r--r--src/kim/lib/kim.exports8
-rw-r--r--src/kim/lib/kim_credential.c336
-rw-r--r--src/kim/lib/kim_identity.c116
-rw-r--r--src/kim/lib/kim_options.c176
-rw-r--r--src/kim/lib/kim_selection_hints.c14
-rw-r--r--src/kim/lib/kim_string.c1
-rw-r--r--src/kim/lib/kim_string_private.h4
-rw-r--r--src/kim/lib/kim_ui.c212
-rw-r--r--src/kim/lib/kim_ui_cli.c324
-rw-r--r--src/kim/lib/kim_ui_cli_private.h24
-rw-r--r--src/kim/lib/kim_ui_gui.c44
-rw-r--r--src/kim/lib/kim_ui_gui_private.h14
-rw-r--r--src/kim/lib/kim_ui_plugin.c44
-rw-r--r--src/kim/lib/kim_ui_plugin_private.h18
-rw-r--r--src/kim/lib/kim_ui_private.h39
-rw-r--r--src/kim/lib/mac/kim_os_library.c2
-rw-r--r--src/kim/lib/mac/kim_os_string.c49
22 files changed, 1707 insertions, 957 deletions
diff --git a/src/include/kim/kim_credential.h b/src/include/kim/kim_credential.h
index ed58a72ae..88ccc5dce 100644
--- a/src/include/kim/kim_credential.h
+++ b/src/include/kim/kim_credential.h
@@ -32,484 +32,532 @@ extern "C" {
#include <kim/kim_types.h>
#include <krb5.h>
- /*!
- * \addtogroup kim_types_reference
- * @{
- */
-
- /*!
- * Possible credential states. Credentials may be:
- * \li valid - The credential can be used.
- * \li expired - The credential's lifetime has been exceeded.
- * \li not_yet_valid - The credential is post dated and the time when
- * it becomes valid has not yet been reached.
- * \li needs_validation - The credential is post-dated and although
- * the time when it becomes valid has been reached
- * it has not yet been validated.
- * \li address_mismatch - The credential contains IP address(es) which do
- * not match the host's local address(es).
- */
- enum kim_credential_state_enum {
- kim_credentials_state_valid = 0,
- kim_credentials_state_expired = 1,
- kim_credentials_state_not_yet_valid = 2,
- kim_credentials_state_needs_validation = 3,
- kim_credentials_state_address_mismatch = 4
- };
-
- /*!
- * The state of a credential. See #kim_credential_state_enum for
- * possible values.
- */
- typedef int kim_credential_state;
-
- /*! @} */
-
- /*!
- * \page kim_credential_overview KIM Credential Overview
- *
- * \section kim_credential_introduction Introduction
- *
- * A Kerberos credential (also called a "Kerberos ticket") is a time-limited
- * token issued by a KDC which authenticates the entity named by the credential's
- * client identity to the service named by the credential's service identity.
- *
- * The kim_credential object contains a single Kerberos credential. KIM credentials
- * objects are always copies of credentials, not references to credentials
- * stored in the cache collection. Modifying credential objects in the ccache
- * collection will not change any existing KIM credential objects.
- *
- * KIM credential APIs are intended for applications and system
- * tools which manage credentials for the user. They are not a substitute for
- * krb5 and GSSAPI functions which obtain service credentials for the purpose
- * of authenticating a client to an application server.
- *
- * \note Many of the APIs listed below have equivalent functions which
- * operate on ccaches. In most cases applications will want to use the
- * ccache versions of these APIs since they automatically store any
- * newly created credentials. See \ref kim_ccache_overview for more
- * information.
- *
- *
- * \section kim_credential_acquire_new Acquiring New Credentials
- *
- * KIM provides the #kim_credential_create_new() API for acquiring new
- * credentials. Credentials can either be obtained for a specific
- * client identity or by specifying #KIM_IDENTITY_ANY to allow
- * the user to choose. Typically callers of this API obtain the client
- * identity using #kim_selection_hints_get_identity(). Depending on the
- * kim_options specified, #kim_credential_create_new() may present a
- * GUI or command line prompt to obtain information from the user.
- *
- * KIM provides the #kim_credential_create_from_keytab() to create credentials
- * using a keytab. A keytab is an on-disk copy of a client identity's secret
- * key. Typically sites use keytabs for client identities that identify a
- * machine or service and protect the keytab with disk permissions. Because
- * a keytab is sufficient to obtain credentials, keytabs will normally only
- * be readable by root, Administrator or some other privileged account.
- * Typically applications use credentials obtained from keytabs to obtain
- * credentials for batch processes. These keytabs and credentials are usually
- * for a special identity used for the batch process rather than a user
- * identity.
- *
- *
- * \section kim_credential_validate Validating Credentials
- *
- * A credential with a start time in the future (ie: after the issue date)
- * is called a post-dated credential. Because the KDC administrator may
- * wish to disable a identity, once the start time is reached, all post-dated
- * credentials must be validated before they can be used. Otherwise an
- * attacker using a compromised account could acquire lots of post-dated
- * credentials to circumvent the acccount being disabled.
- *
- * KIM provides the #kim_credential_validate() API to validate a credential.
- * Note that this API replaces the credential object with a new validated
- * credential object. If you wish to store the new credential in the
- * ccache collection you must either call #kim_credential_store() on the
- * validated credential or use #kim_ccache_validate() instead.
- *
- *
- * \section kim_credential_renew Renewing Credentials
- *
- * A renewable credential can be used to obtain a new identical credential
- * without resending secret information (such as a password) to the KDC.
- * A credential may only be renewed during its renewal lifetime and while
- * valid.
- *
- * KIM provides the #kim_credential_renew() API to renew a credential.
- * Note that this API replaces the credential object with a new renewed
- * credential object. If you wish to store the new credential in the
- * ccache collection you must either call #kim_credential_store() on the
- * renewed credential or use #kim_ccache_renew() instead.
- *
- *
- * \section kim_credential_storing Storing Credentials in the Cache Collection
- *
- * KIM credential objects may be stored in the ccache collection using
- * #kim_credential_store(). This function runs any KIM authentication
- * plugins on the credential and if the plugins return successfully, creates a
- * new ccache for the credential's client identity in the cache collection
- * and stores the credential in that ccache. Any existing ccaches and credentials
- * for that client identity will be overwritten. #kim_credential_store() may
- * optionally return a kim_ccache object for the new ccache if you need to perform
- * further operations on the new ccache.
- *
- * Most of the time if you plan to store the credentials you are manipulating, you
- * should use one of KIM ccache APIs. These functions perform the same operations
- * except that they also call #kim_credential_store() any time the credential object
- * changes. See \ref kim_ccache_overview for more information.
- *
- *
- * \section kim_credential_iterator Iterating over the Credentials in a CCache
- *
- * KIM provides a simple iterator API for iterating over the credentials
- * in a ccache. First, call #kim_credential_iterator_create() to obtain
- * an iterator for a ccache. Then loop calling #kim_credential_iterator_next()
- * until either you find the credential you are looking for or the API
- * returns a NULL credential, indicating that there are no more
- * credentials in the ccache. When you are done with the iterator, call
- * #kim_credential_iterator_free().
- *
- * \note #kim_credential_iterator_next() returns credential objects which
- * must be freed with #kim_credential_free() to avoid leaking memory.
- *
- *
- * \section kim_credential_verify Verifying Credentials
- *
- * When a program acquires TGT credentials for the purpose of authenticating
- * itself to the machine it is running on, it is insufficient for the machine
- * to assume that the caller is authorized just because it got credentials.
- * Instead, the credentials must be verified using a key the local machine.
- * The reason this is necessary is because an attacker can trick the
- * machine into obtaining credentials from any KDC, including malicious ones
- * with the same realm name as the local machine's realm. This exploit is
- * called the Zanarotti attack.
- *
- * In order to avoid the Zanarotti attack, the local machine must authenticate
- * the process in the same way an application server would authenticate a client.
- * Like an application server, the local machine must have its own identity in
- * its realm and a keytab for that identity on its local disk. However,
- * rather than forcing system daemons to use the network-oriented calls in the
- * krb5 and GSS APIs, KIM provides the #kim_credential_verify() API to
- * verify credentials directly.
- *
- * The most common reason for using #kim_credential_verify() is user login.
- * If the local machine wants to use Kerberos to verify the username and password
- * provided by the user, it must call #kim_credential_verify() on the credentials
- * it obtains to make sure they are really from a KDC it trusts. Another common
- * case is a server which is only using Kerberos internally. For example an
- * LDAP or web server might use a username and password obtained over the network
- * to get Kerberos credentials. In order to make sure they aren't being tricked
- * into talking to the wrong KDC, these servers must also call
- * #kim_credential_verify().
- *
- * The Zanarotti attack is only a concern if the act of accessing the machine
- * gives the process special access. Thus a managed cluster machine with
- * Kerberos-authenticated networked home directories does not need to call
- * #kim_credential_verify(). Even though an attacker can log in as any user on
- * the cluster machine, the attacker can't actually access any of the user's data
- * or use any of their privileges because those are all authenticated via
- * Kerberized application servers (and thus require actually having credentials
- * for the real local realm).
- *
- * #kim_credential_verify() provides an option to
- * return success even if the machine's host key is not present. This option
- * exists for sites which have a mix of different machines, some of which are
- * vulnerable to the Zanarotti attack and some are not. If this option is used,
- * it is the responsiblity of the machine's maintainer to obtain a keytab
- * for their machine if it needs one.
- *
- *
- * \section kim_credential_properties Examining Credential Properties
- *
- * \li #kim_credential_get_client_identity()
- * returns the credential's client identity.
- *
- * \li #kim_credential_get_service_identity()
- * returns the credential's service identity.
- *
- * \li #kim_credential_is_tgt()
- * returns whether the credential is a TGT (ie: "ticket-granting ticket"). TGTs are
- * credentials for the krbtgt service: a service identity of the form "krbtgt/<REALM>@<REALM>".
- * These credentials allow the entity named by the client identity to obtain
- * additional service credentials without resending shared secrets (such as a password)
- * to the KDC. Kerberos uses TGTs to provide single sign-on authentication.
- *
- * \li #kim_credential_is_valid()
- * returns whether the credential is valid and if not why the credential is not valid.
- *
- * \li #kim_credential_get_start_time()
- * returns when the credential will become valid.
- * Credentials may be "post-dated" which means that their lifetime starts sometime
- * in the future. Note that when a post-dated credential's start time is reached,
- * the credential must be validated. See \ref kim_credential_validate for more information.
- *
- * \li #kim_credential_get_expiration_time()
- * returns when the credential will expire.
- * Credentials are time limited by the lifetime of the credential. While you can
- * request a credential of any lifetime, the KDC limits the credential lifetime
- * to a administrator-defined maximum. Typically credential lifetime range from 10
- * to 21 hours.
- *
- * \li #kim_credential_get_renewal_expiration_time()
- * returns when the credential will no longer be renewable.
- * Valid credentials may be renewed up until their renewal expiration time.
- * Renewing credentials acquires a fresh set of credentials with a full lifetime
- * without resending secrets to the KDC (such as a password). If credentials are
- * not renewable, this function will return an error.
- *
- *
- * See \ref kim_credential_reference and \ref kim_credential_iterator_reference for
- * information on specific APIs.
- */
-
- /*!
- * \defgroup kim_credential_iterator_reference KIM Credential Iterator Reference Documentation
- * @{
- */
-
- /*!
- * \param out_credential_iterator on exit, a credential iterator object for \a in_ccache.
- * Must be freed with kim_credential_iterator_free().
- * \param in_ccache a ccache object.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Get a credential iterator to enumerate credentials in a ccache.
- */
-
- kim_error kim_credential_iterator_create (kim_credential_iterator *out_credential_iterator,
- kim_ccache in_ccache);
-
- /*!
- * \param in_credential_iterator a credential iterator object.
- * \param out_credential on exit, the next credential in the ccache iterated by
- * \a in_credential_iterator. Must be freed with
- * kim_credential_free(). If there are no more credentials
- * this argument will be set to NULL.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Get the next credential in a ccache.
- */
-
- kim_error kim_credential_iterator_next (kim_credential_iterator in_credential_iterator,
- kim_credential *out_credential);
-
- /*!
- * \param io_credential_iterator a credential iterator object to be freed. Set to NULL on exit.
- * \brief Free memory associated with a credential iterator.
- */
- void kim_credential_iterator_free (kim_credential_iterator *io_credential_iterator);
-
- /*!@}*/
-
- /*!
- * \defgroup kim_credential_reference KIM Credential Reference Documentation
- * @{
- */
-
- /*!
- * \param out_credential on exit, a new credential object containing a newly acquired
- * initial credential. Must be freed with kim_credential_free().
- * \param in_client_identity a client identity to obtain a credential for. Specify NULL to
- * allow the user to choose the identity
- * \param in_options options to control credential acquisition.
- * \note Depending on the kim_options specified, #kim_credential_create_new() may
- * present a GUI or command line prompt to obtain information from the user.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Acquire a new initial credential.
- * \sa kim_ccache_create_new
- */
- kim_error kim_credential_create_new (kim_credential *out_credential,
- kim_identity in_client_identity,
- kim_options in_options);
-
- /*!
- * \param out_credential on exit, a new credential object containing an initial credential
- * for \a in_identity obtained using \a in_keytab.
- * Must be freed with kim_credential_free().
- * \param in_identity a client identity to obtain a credential for. Specify NULL for
- * the first identity in the keytab.
- * \param in_options options to control credential acquisition.
- * \param in_keytab a path to a keytab. Specify NULL for the default keytab location.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Acquire a new initial credential from a keytab.
- * \sa kim_ccache_create_from_keytab
- */
- kim_error kim_credential_create_from_keytab (kim_credential *out_credential,
- kim_identity in_identity,
- kim_options in_options,
- kim_string in_keytab);
-
- /*!
- * \param out_credential on exit, a new credential object which is a copy of \a in_krb5_creds.
- * Must be freed with kim_credential_free().
- * \param in_krb5_context the krb5 context used to create \a in_krb5_creds.
- * \param in_krb5_creds a krb5 credential object.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Copy a credential from a krb5 credential object.
- */
- kim_error kim_credential_create_from_krb5_creds (kim_credential *out_credential,
- krb5_context in_krb5_context,
- krb5_creds *in_krb5_creds);
-
- /*!
- * \param out_credential on exit, a new credential object which is a copy of \a in_credential.
- * Must be freed with kim_credential_free().
- * \param in_credential a credential object.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Copy a credential object.
- */
- kim_error kim_credential_copy (kim_credential *out_credential,
- kim_credential in_credential);
-
- /*!
- * \param in_credential a credential object.
- * \param in_krb5_context a krb5 context which will be used to create \a out_krb5_creds.
- * \param out_krb5_creds on exit, a new krb5 creds object which is a copy of \a in_credential.
- * Must be freed with krb5_free_creds().
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Get a krb5 credentials object for a credential object.
- */
- kim_error kim_credential_get_krb5_creds (kim_credential in_credential,
- krb5_context in_krb5_context,
- krb5_creds **out_krb5_creds);
-
- /*!
- * \param in_credential a credential object.
- * \param out_client_identity on exit, an identity object containing the client identity of
- * \a in_credential. Must be freed with kim_identity_free().
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Get the client identity of a credential object.
- */
- kim_error kim_credential_get_client_identity (kim_credential in_credential,
- kim_identity *out_client_identity);
-
- /*!
- * \param in_credential a credential object.
- * \param out_service_identity on exit, an identity object containing the service identity of
- * \a in_credential. Must be freed with kim_identity_free().
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Get the service identity of a credential object.
- */
- kim_error kim_credential_get_service_identity (kim_credential in_credential,
- kim_identity *out_service_identity);
-
- /*!
- * \param in_credential a credential object.
- * \param out_is_tgt on exit, whether or not the credential is a TGT.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Check if a credential is a ticket granting ticket.
- */
- kim_error kim_credential_is_tgt (kim_credential in_credential,
- kim_boolean *out_is_tgt);
-
- /*!
- * \param in_credential a credential object.
- * \param out_state on exit, the state of the credential. See #kim_credential_state_enum
- * for the possible values of \a out_state.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Check the state of a credential (valid, expired, postdated, etc).
- */
- kim_error kim_credential_get_state (kim_credential in_credential,
- kim_credential_state *out_state);
-
- /*!
- * \param in_credential a credential object.
- * \param out_start_time on exit, the time when \a in_credential becomes valid.
- * May be in the past or future.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Get the time when the credentials become valid.
- * \sa kim_ccache_get_start_time
- */
- kim_error kim_credential_get_start_time (kim_credential in_credential,
- kim_time *out_start_time);
-
- /*!
- * \param in_credential a credential object.
- * \param out_expiration_time on exit, the time when \a in_credential will expire.
- * May be in the past or future.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Get the time when the credentials will expire.
- * \sa kim_ccache_get_expiration_time
- */
- kim_error kim_credential_get_expiration_time (kim_credential in_credential,
- kim_time *out_expiration_time);
-
- /*!
- * \param in_credential a credential object.
- * \param out_renewal_expiration_time on exit, the time when \a in_credential will no longer
- * be renewable. May be in the past or future.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Get the time when the credentials will no longer be renewable.
- * \sa kim_ccache_get_renewal_expiration_time
- */
- kim_error kim_credential_get_renewal_expiration_time (kim_credential in_credential,
- kim_time *out_renewal_expiration_time);
-
-
- /*!
- * \param in_credential a credential object.
- * \param in_client_identity a client identity.
- * \param out_ccache on exit, a ccache object containing \a in_credential with the client
- * identity \a in_client_identity. Must be freed with kim_ccache_free().
- * Specify NULL if you don't want this return value.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Store a credential in a ccache in the cache collection.
- */
- kim_error kim_credential_store (kim_credential in_credential,
- kim_identity in_client_identity,
- kim_ccache *out_ccache);
-
- /*!
- * \param in_credential a TGT credential to be verified.
- * \param in_service_identity a service identity to look for in the keytab. Specify
- * KIM_IDENTITY_ANY to use the default service identity
- * (usually host/<host's FQDN>@<host's local realm>).
- * \param in_keytab a path to a keytab. Specify NULL for the default keytab location.
- * \param in_fail_if_no_service_key whether or not the absence of a key for \a in_service_identity
- * in the host's keytab will cause a failure.
- * \note specifying FALSE for \a in_fail_if_no_service_key may expose the calling program to
- * the Zanarotti attack if the host has no keytab installed.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Verify a TGT credential.
- * \sa kim_ccache_verify
- */
- kim_error kim_credential_verify (kim_credential in_credential,
- kim_identity in_service_identity,
- kim_string in_keytab,
- kim_boolean in_fail_if_no_service_key);
-
- /*!
- * \param io_credential a TGT credential to be renewed. On exit, the old credential
- * object will be freed and \a io_credential will be replaced
- * with a new renewed credential. The new credential must be freed
- * with kim_credential_free().
- * \param in_options initial credential options.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Renew a TGT credential.
- * \sa kim_ccache_renew
- */
- kim_error kim_credential_renew (kim_credential *io_credential,
- kim_options in_options);
-
- /*!
- * \param io_credential a credential object to be validated. On exit, the old credential
- * object will be freed and \a io_credential will be replaced
- * with a new validated credential. The new credential must be freed
- * with kim_credential_free().
- * \param in_options initial credential options.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Validate a TGT credential.
- * \sa kim_ccache_validate
- */
- kim_error kim_credential_validate (kim_credential *io_credential,
- kim_options in_options);
-
- /*!
- * \param io_credential the credential object to be freed. Set to NULL on exit.
- * \brief Free memory associated with a credential object.
- */
- void kim_credential_free (kim_credential *io_credential);
-
- /*!@}*/
+/*!
+ * \addtogroup kim_types_reference
+ * @{
+ */
+
+/*!
+ * Possible credential states. Credentials may be:
+ * \li valid - The credential can be used.
+ * \li expired - The credential's lifetime has been exceeded.
+ * \li not_yet_valid - The credential is post dated and the time when
+ * it becomes valid has not yet been reached.
+ * \li needs_validation - The credential is post-dated and although
+ * the time when it becomes valid has been reached
+ * it has not yet been validated.
+ * \li address_mismatch - The credential contains IP address(es) which do
+ * not match the host's local address(es).
+ */
+enum kim_credential_state_enum {
+ kim_credentials_state_valid = 0,
+ kim_credentials_state_expired = 1,
+ kim_credentials_state_not_yet_valid = 2,
+ kim_credentials_state_needs_validation = 3,
+ kim_credentials_state_address_mismatch = 4
+};
+
+/*!
+ * The state of a credential. See #kim_credential_state_enum for
+ * possible values.
+ */
+typedef int kim_credential_state;
+
+/*! @} */
+
+/*!
+ * \page kim_credential_overview KIM Credential Overview
+ *
+ * \section kim_credential_introduction Introduction
+ *
+ * A Kerberos credential (also called a "Kerberos ticket") is a time-limited
+ * token issued by a KDC which authenticates the entity named by the credential's
+ * client identity to the service named by the credential's service identity.
+ *
+ * The kim_credential object contains a single Kerberos credential. KIM credentials
+ * objects are always copies of credentials, not references to credentials
+ * stored in the cache collection. Modifying credential objects in the ccache
+ * collection will not change any existing KIM credential objects.
+ *
+ * KIM credential APIs are intended for applications and system
+ * tools which manage credentials for the user. They are not a substitute for
+ * krb5 and GSSAPI functions which obtain service credentials for the purpose
+ * of authenticating a client to an application server.
+ *
+ * \note Many of the APIs listed below have equivalent functions which
+ * operate on ccaches. In most cases applications will want to use the
+ * ccache versions of these APIs since they automatically store any
+ * newly created credentials. See \ref kim_ccache_overview for more
+ * information.
+ *
+ *
+ * \section kim_credential_acquire_new Acquiring New Credentials
+ *
+ * KIM provides the #kim_credential_create_new() API for acquiring new
+ * credentials. Credentials can either be obtained for a specific
+ * client identity or by specifying #KIM_IDENTITY_ANY to allow
+ * the user to choose. Typically callers of this API obtain the client
+ * identity using #kim_selection_hints_get_identity(). Depending on the
+ * kim_options specified, #kim_credential_create_new() may present a
+ * GUI or command line prompt to obtain information from the user.
+ *
+ * KIM provides the #kim_credential_create_from_keytab() to create credentials
+ * using a keytab. A keytab is an on-disk copy of a client identity's secret
+ * key. Typically sites use keytabs for client identities that identify a
+ * machine or service and protect the keytab with disk permissions. Because
+ * a keytab is sufficient to obtain credentials, keytabs will normally only
+ * be readable by root, Administrator or some other privileged account.
+ * Typically applications use credentials obtained from keytabs to obtain
+ * credentials for batch processes. These keytabs and credentials are usually
+ * for a special identity used for the batch process rather than a user
+ * identity.
+ *
+ *
+ * \section kim_credential_validate Validating Credentials
+ *
+ * A credential with a start time in the future (ie: after the issue date)
+ * is called a post-dated credential. Because the KDC administrator may
+ * wish to disable a identity, once the start time is reached, all post-dated
+ * credentials must be validated before they can be used. Otherwise an
+ * attacker using a compromised account could acquire lots of post-dated
+ * credentials to circumvent the acccount being disabled.
+ *
+ * KIM provides the #kim_credential_validate() API to validate a credential.
+ * Note that this API replaces the credential object with a new validated
+ * credential object. If you wish to store the new credential in the
+ * ccache collection you must either call #kim_credential_store() on the
+ * validated credential or use #kim_ccache_validate() instead.
+ *
+ *
+ * \section kim_credential_renew Renewing Credentials
+ *
+ * A renewable credential can be used to obtain a new identical credential
+ * without resending secret information (such as a password) to the KDC.
+ * A credential may only be renewed during its renewal lifetime and while
+ * valid.
+ *
+ * KIM provides the #kim_credential_renew() API to renew a credential.
+ * Note that this API replaces the credential object with a new renewed
+ * credential object. If you wish to store the new credential in the
+ * ccache collection you must either call #kim_credential_store() on the
+ * renewed credential or use #kim_ccache_renew() instead.
+ *
+ *
+ * \section kim_credential_storing Storing Credentials in the Cache Collection
+ *
+ * KIM credential objects may be stored in the ccache collection using
+ * #kim_credential_store(). This function runs any KIM authentication
+ * plugins on the credential and if the plugins return successfully, creates a
+ * new ccache for the credential's client identity in the cache collection
+ * and stores the credential in that ccache. Any existing ccaches and credentials
+ * for that client identity will be overwritten. #kim_credential_store() may
+ * optionally return a kim_ccache object for the new ccache if you need to perform
+ * further operations on the new ccache.
+ *
+ * Most of the time if you plan to store the credentials you are manipulating, you
+ * should use one of KIM ccache APIs. These functions perform the same operations
+ * except that they also call #kim_credential_store() any time the credential object
+ * changes. See \ref kim_ccache_overview for more information.
+ *
+ *
+ * \section kim_credential_iterator Iterating over the Credentials in a CCache
+ *
+ * KIM provides a simple iterator API for iterating over the credentials
+ * in a ccache. First, call #kim_credential_iterator_create() to obtain
+ * an iterator for a ccache. Then loop calling #kim_credential_iterator_next()
+ * until either you find the credential you are looking for or the API
+ * returns a NULL credential, indicating that there are no more
+ * credentials in the ccache. When you are done with the iterator, call
+ * #kim_credential_iterator_free().
+ *
+ * \note #kim_credential_iterator_next() returns credential objects which
+ * must be freed with #kim_credential_free() to avoid leaking memory.
+ *
+ *
+ * \section kim_credential_verify Verifying Credentials
+ *
+ * When a program acquires TGT credentials for the purpose of authenticating
+ * itself to the machine it is running on, it is insufficient for the machine
+ * to assume that the caller is authorized just because it got credentials.
+ * Instead, the credentials must be verified using a key the local machine.
+ * The reason this is necessary is because an attacker can trick the
+ * machine into obtaining credentials from any KDC, including malicious ones
+ * with the same realm name as the local machine's realm. This exploit is
+ * called the Zanarotti attack.
+ *
+ * In order to avoid the Zanarotti attack, the local machine must authenticate
+ * the process in the same way an application server would authenticate a client.
+ * Like an application server, the local machine must have its own identity in
+ * its realm and a keytab for that identity on its local disk. However,
+ * rather than forcing system daemons to use the network-oriented calls in the
+ * krb5 and GSS APIs, KIM provides the #kim_credential_verify() API to
+ * verify credentials directly.
+ *
+ * The most common reason for using #kim_credential_verify() is user login.
+ * If the local machine wants to use Kerberos to verify the username and password
+ * provided by the user, it must call #kim_credential_verify() on the credentials
+ * it obtains to make sure they are really from a KDC it trusts. Another common
+ * case is a server which is only using Kerberos internally. For example an
+ * LDAP or web server might use a username and password obtained over the network
+ * to get Kerberos credentials. In order to make sure they aren't being tricked
+ * into talking to the wrong KDC, these servers must also call
+ * #kim_credential_verify().
+ *
+ * The Zanarotti attack is only a concern if the act of accessing the machine
+ * gives the process special access. Thus a managed cluster machine with
+ * Kerberos-authenticated networked home directories does not need to call
+ * #kim_credential_verify(). Even though an attacker can log in as any user on
+ * the cluster machine, the attacker can't actually access any of the user's data
+ * or use any of their privileges because those are all authenticated via
+ * Kerberized application servers (and thus require actually having credentials
+ * for the real local realm).
+ *
+ * #kim_credential_verify() provides an option to
+ * return success even if the machine's host key is not present. This option
+ * exists for sites which have a mix of different machines, some of which are
+ * vulnerable to the Zanarotti attack and some are not. If this option is used,
+ * it is the responsiblity of the machine's maintainer to obtain a keytab
+ * for their machine if it needs one.
+ *
+ *
+ * \section kim_credential_properties Examining Credential Properties
+ *
+ * \li #kim_credential_get_client_identity()
+ * returns the credential's client identity.
+ *
+ * \li #kim_credential_get_service_identity()
+ * returns the credential's service identity.
+ *
+ * \li #kim_credential_is_tgt()
+ * returns whether the credential is a TGT (ie: "ticket-granting ticket"). TGTs are
+ * credentials for the krbtgt service: a service identity of the form "krbtgt/<REALM>@<REALM>".
+ * These credentials allow the entity named by the client identity to obtain
+ * additional service credentials without resending shared secrets (such as a password)
+ * to the KDC. Kerberos uses TGTs to provide single sign-on authentication.
+ *
+ * \li #kim_credential_is_valid()
+ * returns whether the credential is valid and if not why the credential is not valid.
+ *
+ * \li #kim_credential_get_start_time()
+ * returns when the credential will become valid.
+ * Credentials may be "post-dated" which means that their lifetime starts sometime
+ * in the future. Note that when a post-dated credential's start time is reached,
+ * the credential must be validated. See \ref kim_credential_validate for more information.
+ *
+ * \li #kim_credential_get_expiration_time()
+ * returns when the credential will expire.
+ * Credentials are time limited by the lifetime of the credential. While you can
+ * request a credential of any lifetime, the KDC limits the credential lifetime
+ * to a administrator-defined maximum. Typically credential lifetime range from 10
+ * to 21 hours.
+ *
+ * \li #kim_credential_get_renewal_expiration_time()
+ * returns when the credential will no longer be renewable.
+ * Valid credentials may be renewed up until their renewal expiration time.
+ * Renewing credentials acquires a fresh set of credentials with a full lifetime
+ * without resending secrets to the KDC (such as a password). If credentials are
+ * not renewable, this function will return an error.
+ *
+ *
+ * See \ref kim_credential_reference and \ref kim_credential_iterator_reference for
+ * information on specific APIs.
+ */
+
+/*!
+ * \defgroup kim_credential_iterator_reference KIM Credential Iterator Reference Documentation
+ * @{
+ */
+
+/*!
+ * \param out_credential_iterator on exit, a credential iterator object for \a in_ccache.
+ * Must be freed with kim_credential_iterator_free().
+ * \param in_ccache a ccache object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Get a credential iterator to enumerate credentials in a ccache.
+ */
+
+kim_error kim_credential_iterator_create (kim_credential_iterator *out_credential_iterator,
+ kim_ccache in_ccache);
+
+/*!
+ * \param in_credential_iterator a credential iterator object.
+ * \param out_credential on exit, the next credential in the ccache iterated by
+ * \a in_credential_iterator. Must be freed with
+ * kim_credential_free(). If there are no more credentials
+ * this argument will be set to NULL.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Get the next credential in a ccache.
+ */
+
+kim_error kim_credential_iterator_next (kim_credential_iterator in_credential_iterator,
+ kim_credential *out_credential);
+
+/*!
+ * \param io_credential_iterator a credential iterator object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with a credential iterator.
+ */
+void kim_credential_iterator_free (kim_credential_iterator *io_credential_iterator);
+
+/*!@}*/
+
+/*!
+ * \defgroup kim_credential_reference KIM Credential Reference Documentation
+ * @{
+ */
+
+/*!
+ * \param out_credential on exit, a new credential object containing a newly acquired
+ * initial credential. Must be freed with kim_credential_free().
+ * \param in_client_identity a client identity to obtain a credential for. Specify NULL to
+ * allow the user to choose the identity
+ * \param in_options options to control credential acquisition.
+ * \note Depending on the kim_options specified, #kim_credential_create_new() may
+ * present a GUI or command line prompt to obtain information from the user.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Acquire a new initial credential.
+ * \sa kim_ccache_create_new
+ */
+kim_error kim_credential_create_new (kim_credential *out_credential,
+ kim_identity in_client_identity,
+ kim_options in_options);
+
+/*!
+ * \param out_credential on exit, a new credential object containing an initial credential
+ * for \a in_identity obtained using \a in_keytab.
+ * Must be freed with kim_credential_free().
+ * \param in_identity a client identity to obtain a credential for. Specify NULL for
+ * the first identity in the keytab.
+ * \param in_options options to control credential acquisition.
+ * \param in_keytab a path to a keytab. Specify NULL for the default keytab location.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Acquire a new initial credential from a keytab.
+ * \sa kim_ccache_create_from_keytab
+ */
+kim_error kim_credential_create_from_keytab (kim_credential *out_credential,
+ kim_identity in_identity,
+ kim_options in_options,
+ kim_string in_keytab);
+
+/*!
+ * \param out_credential on exit, a new credential object which is a copy of \a in_krb5_creds.
+ * Must be freed with kim_credential_free().
+ * \param in_krb5_context the krb5 context used to create \a in_krb5_creds.
+ * \param in_krb5_creds a krb5 credential object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Copy a credential from a krb5 credential object.
+ */
+kim_error kim_credential_create_from_krb5_creds (kim_credential *out_credential,
+ krb5_context in_krb5_context,
+ krb5_creds *in_krb5_creds);
+
+/*!
+ * \param out_credential on exit, a new credential object containing a change
+ * password credential for \a in_identity.
+ * Must be freed with kim_credential_free().
+ * \param in_identity a client identity to obtain a change password credential for.
+ * \param in_old_password the current password for \a in_identity. May be
+ * an expired password.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Obtain a credential for changing an identity's password.
+ * \sa kim_credential_change_password
+ */
+kim_error kim_credential_create_for_change_password (kim_credential *out_credential,
+ kim_identity in_identity,
+ kim_string in_old_password);
+
+/*!
+ * \param out_credential on exit, a new credential object which is a copy of \a in_credential.
+ * Must be freed with kim_credential_free().
+ * \param in_credential a credential object.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Copy a credential object.
+ */
+kim_error kim_credential_copy (kim_credential *out_credential,
+ kim_credential in_credential);
+
+/*!
+ * \param in_credential a credential object.
+ * \param in_krb5_context a krb5 context which will be used to create \a out_krb5_creds.
+ * \param out_krb5_creds on exit, a new krb5 creds object which is a copy of \a in_credential.
+ * Must be freed with krb5_free_creds().
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Get a krb5 credentials object for a credential object.
+ */
+kim_error kim_credential_get_krb5_creds (kim_credential in_credential,
+ krb5_context in_krb5_context,
+ krb5_creds **out_krb5_creds);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_client_identity on exit, an identity object containing the client identity of
+ * \a in_credential. Must be freed with kim_identity_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Get the client identity of a credential object.
+ */
+kim_error kim_credential_get_client_identity (kim_credential in_credential,
+ kim_identity *out_client_identity);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_service_identity on exit, an identity object containing the service identity of
+ * \a in_credential. Must be freed with kim_identity_free().
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Get the service identity of a credential object.
+ */
+kim_error kim_credential_get_service_identity (kim_credential in_credential,
+ kim_identity *out_service_identity);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_is_tgt on exit, whether or not the credential is a TGT.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Check if a credential is a ticket granting ticket.
+ */
+kim_error kim_credential_is_tgt (kim_credential in_credential,
+ kim_boolean *out_is_tgt);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_state on exit, the state of the credential. See #kim_credential_state_enum
+ * for the possible values of \a out_state.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Check the state of a credential (valid, expired, postdated, etc).
+ */
+kim_error kim_credential_get_state (kim_credential in_credential,
+ kim_credential_state *out_state);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_start_time on exit, the time when \a in_credential becomes valid.
+ * May be in the past or future.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Get the time when the credentials become valid.
+ * \sa kim_ccache_get_start_time
+ */
+kim_error kim_credential_get_start_time (kim_credential in_credential,
+ kim_time *out_start_time);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_expiration_time on exit, the time when \a in_credential will expire.
+ * May be in the past or future.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Get the time when the credentials will expire.
+ * \sa kim_ccache_get_expiration_time
+ */
+kim_error kim_credential_get_expiration_time (kim_credential in_credential,
+ kim_time *out_expiration_time);
+
+/*!
+ * \param in_credential a credential object.
+ * \param out_renewal_expiration_time on exit, the time when \a in_credential will no longer
+ * be renewable. May be in the past or future.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Get the time when the credentials will no longer be renewable.
+ * \sa kim_ccache_get_renewal_expiration_time
+ */
+kim_error kim_credential_get_renewal_expiration_time (kim_credential in_credential,
+ kim_time *out_renewal_expiration_time);
+
+
+/*!
+ * \param in_credential a credential object.
+ * \param in_client_identity a client identity.
+ * \param out_ccache on exit, a ccache object containing \a in_credential with the client
+ * identity \a in_client_identity. Must be freed with kim_ccache_free().
+ * Specify NULL if you don't want this return value.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Store a credential in a ccache in the cache collection.
+ */
+kim_error kim_credential_store (kim_credential in_credential,
+ kim_identity in_client_identity,
+ kim_ccache *out_ccache);
+
+/*!
+ * \param in_credential a TGT credential to be verified.
+ * \param in_service_identity a service identity to look for in the keytab. Specify
+ * KIM_IDENTITY_ANY to use the default service identity
+ * (usually host/<host's FQDN>@<host's local realm>).
+ * \param in_keytab a path to a keytab. Specify NULL for the default keytab location.
+ * \param in_fail_if_no_service_key whether or not the absence of a key for \a in_service_identity
+ * in the host's keytab will cause a failure.
+ * \note specifying FALSE for \a in_fail_if_no_service_key may expose the calling program to
+ * the Zanarotti attack if the host has no keytab installed.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Verify a TGT credential.
+ * \sa kim_ccache_verify
+ */
+kim_error kim_credential_verify (kim_credential in_credential,
+ kim_identity in_service_identity,
+ kim_string in_keytab,
+ kim_boolean in_fail_if_no_service_key);
+
+/*!
+ * \param io_credential a TGT credential to be renewed. On exit, the old credential
+ * object will be freed and \a io_credential will be replaced
+ * with a new renewed credential. The new credential must be freed
+ * with kim_credential_free().
+ * \param in_options initial credential options.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Renew a TGT credential.
+ * \sa kim_ccache_renew
+ */
+kim_error kim_credential_renew (kim_credential *io_credential,
+ kim_options in_options);
+
+/*!
+ * \param io_credential a credential object to be validated. On exit, the old credential
+ * object will be freed and \a io_credential will be replaced
+ * with a new validated credential. The new credential must be freed
+ * with kim_credential_free().
+ * \param in_options initial credential options.
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Validate a TGT credential.
+ * \sa kim_ccache_validate
+ */
+kim_error kim_credential_validate (kim_credential *io_credential,
+ kim_options in_options);
+
+/*!
+ * \param in_credential a credential object containing a change
+ * password credential. Use
+ * #kim_credential_change_password to obtain
+ * a change password credential.
+ * \param in_identity an identity to change the password for. May
+ * be different than the identity the credential
+ * is for.
+ * \param in_new_password the password to change the identity to.
+ * \param out_rejected_err on exit, 0 if the password change was
+ * successful or an error describing why the
+ * new password was rejected.
+ * \param out_rejected_message on exit, if \a out_rejected_err is non-zero
+ * this argument will contain an error message
+ * for \a out_rejected_err. Pass NULL if you
+ * do not want this error string. Must be
+ * freed with #kim_string_free();
+ * \param out_rejected_description on exit, if \a out_rejected_err is non-zero
+ * this argument will contain an string describing
+ * why \a in_new_password was rejected. Pass NULL
+ * if you do not want this error string. Must be
+ * freed with #kim_string_free();
+ * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
+ * \brief Change an identity's password.
+ * \sa kim_credential_create_for_change_password
+ */
+kim_error kim_credential_change_password (kim_credential in_credential,
+ kim_identity in_identity,
+ kim_string in_new_password,
+ kim_error *out_rejected_err,
+ kim_string *out_rejected_message,
+ kim_string *out_rejected_description);
+
+/*!
+ * \param io_credential the credential object to be freed. Set to NULL on exit.
+ * \brief Free memory associated with a credential object.
+ */
+void kim_credential_free (kim_credential *io_credential);
+
+/*!@}*/
#ifdef __cplusplus
diff --git a/src/include/kim/kim_identity.h b/src/include/kim/kim_identity.h
index 4461c3163..f09c24aa7 100644
--- a/src/include/kim/kim_identity.h
+++ b/src/include/kim/kim_identity.h
@@ -256,29 +256,12 @@ kim_error kim_identity_get_krb5_principal (kim_identity in_identity,
/*!
* \param in_identity an identity object whose password will be changed.
- * \param in_options initial credential options to be used if a new credential is obtained.
* \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
* \brief Change the password for an identity.
* \note kim_identity_change_password() will acquire a temporary credential to change
- * the password. It uses the \a in_options structure to obtain information about the desired
- * prompter and current password.
+ * the password.
*/
-kim_error kim_identity_change_password (kim_identity in_identity,
- kim_options in_options);
-
-/*!
- * \param in_identity an identity object whose password will be changed.
- * \param in_options initial credential options to be used if a new credential is obtained.
- * \param in_new_password a string representation of the identity's new password.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Change the password for an identity to a caller-provided new password.
- * \note kim_identity_change_password_with_passwords() will acquire a temporary credential
- * to change the password. It uses the \a in_options structure to obtain information about
- * the desired prompter and current password.
- */
-kim_error kim_identity_change_password_to_password (kim_identity in_identity,
- kim_options in_options,
- kim_string in_new_password);
+kim_error kim_identity_change_password (kim_identity in_identity);
/*!
* \param io_identity the identity object to be freed. Set to NULL on exit.
diff --git a/src/include/kim/kim_options.h b/src/include/kim/kim_options.h
index f5b975cf3..2c82b3ef5 100644
--- a/src/include/kim/kim_options.h
+++ b/src/include/kim/kim_options.h
@@ -46,70 +46,6 @@ extern "C" {
*/
#define KIM_OPTIONS_START_IMMEDIATELY ((kim_time_t) 0)
-/*!
- * The type of prompt which needs to be displayed.
- * This value determines what type of user interface is displayed.
- * See \ref kim_options_custom_prompt_callback for more information.
- */
-typedef uint32_t kim_prompt_type;
-
-enum kim_prompt_type_enum {
- kim_prompt_type_password = 0,
- kim_prompt_type_challenge = 1
-};
-
-/*!
- * 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_prompt_type in_type,
- kim_string in_title,
- kim_string in_message,
- kim_string in_description,
- char **out_reply);
-
-/*!
- * The default prompt callback.
- * See \ref kim_options_custom_prompt_callback for more information.
- */
-kim_error kim_prompt_callback_default (kim_prompt_type in_type,
- kim_string in_title,
- kim_string in_message,
- kim_string in_description,
- char **out_reply);
-
-/*!
- * The graphical prompt callback.
- * See \ref kim_options_custom_prompt_callback for more information.
- */
-kim_error kim_prompt_callback_gui (kim_prompt_type in_type,
- kim_string in_title,
- kim_string in_message,
- kim_string in_description,
- 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_prompt_type in_type,
- kim_string in_title,
- kim_string in_message,
- kim_string in_description,
- char **out_reply);
-
-/*!
- * The prompt callback which always returns an error.
- * Use to turn off prompting entirely.
- * \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_prompt_type in_type,
- kim_string in_title,
- kim_string in_message,
- kim_string in_description,
- char **out_reply);
-
/*! @} */
/*!
@@ -126,34 +62,6 @@ kim_error kim_prompt_callback_none (kim_prompt_type in_type,
* KIM options fall into two major categories: options for controlling how credentials are
* acquired and options for controlling what properties the newly acquired credentials will have:
*
- * \section kim_options_credential_acquisition Options for Controlling Credential Acquisition
- *
- * In order to acquire credentials, Kerberos needs to obtain one or more secrets from the user.
- * These secrets may be a certificate, password, SecurID pin, or information from a smart card.
- * If obtaining the secret requires interaction with the user, the Kerberos libraries call a
- * "prompter callback" to display a dialog or command line prompt to request information from
- * the user. If you want to provide your own custom dialogs or command line prompts,
- * the KIM APIs provide a mechanism for replacing the default prompt callbacks with your own.
- *
- * \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 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
- * a dialog and returns an error if there is no graphical access. #kim_prompt_callback_cli
- * only presents a command line interface and returns an error if there is no controlling
- * terminal available. #kim_prompt_callback_none always returns an error.
- *
- * 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.
- * 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.
- *
* \section kim_options_credential_properties Options for Controlling Credential Properties
*
* Kerberos credentials have a number of different properties which can be requested
@@ -286,61 +194,6 @@ kim_error kim_options_copy (kim_options *out_options,
kim_options in_options);
/*!
- * \param io_options an options object to modify.
- * \param in_prompt_callback a prompt callback function.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Set the prompt callback for obtaining information from the user.
- * \par Default value
- * #kim_prompt_callback_default
- * \sa kim_options_get_prompt_callback()
- */
-kim_error kim_options_set_prompt_callback (kim_options io_options,
- kim_prompt_callback in_prompt_callback);
-
-/*!
- * \param in_options an options object.
- * \param out_prompt_callback on exit, the prompt callback specified by 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 prompt callback for obtaining information from the user.
- * \par Default value
- * #kim_prompt_callback_default
- * \sa kim_options_set_prompt_callback()
- */
-kim_error kim_options_get_prompt_callback (kim_options in_options,
- kim_prompt_callback *out_prompt_callback);
-
-/*!
- * \param io_options an options object to modify.
- * \param in_data a pointer to caller-specific data.
- * \return On success, #KIM_NO_ERROR. On failure, an error code representing the failure.
- * \brief Set caller-specific data for use in library callbacks.
- * \note This option can be used by the caller to store a pointer to data needed when handling a
- * callback. The KIM library does not use this options data in any way.
- * \par Default value
- * NULL (no data is set by default)
- * \sa kim_options_get_data()
- */
-kim_error kim_options_set_data (kim_options io_options,
- const void *in_data);
-
-/*!
- * \param in_options an options object.
- * \param out_data on exit, the pointer to caller specific data specified by 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 caller-specific data for use in library callbacks.
- * \note This option can be used by the caller to store a pointer to data needed when handling a
- * callback. The KIM library does not use this options data in any way.
- * \par Default value
- * NULL (no data is set by default)
- * \sa kim_options_set_data()
- */
-kim_error kim_options_get_data (kim_options in_options,
- const void **out_data);
-
-/*!
* \param io_options an options object to modify.
* \param in_start_time a start date (in seconds since January 1, 1970). Set to
* #KIM_OPTIONS_START_IMMEDIATELY for the acquired credential to be valid
diff --git a/src/include/kim/kim_ui_plugin.h b/src/include/kim/kim_ui_plugin.h
index d7fd6e1b7..b7d48ad89 100644
--- a/src/include/kim/kim_ui_plugin.h
+++ b/src/include/kim/kim_ui_plugin.h
@@ -29,7 +29,28 @@
extern "C" {
#endif
+/*!
+ * The type of prompt which needs to be displayed.
+ * This value determines what type of user interface is displayed.
+ * See \ref kim_options_custom_prompt_callback for more information.
+ */
+typedef uint32_t kim_prompt_type;
+
+enum kim_prompt_type_enum {
+ kim_prompt_type_password = 0,
+ kim_prompt_type_preauth = 1
+};
+
/*
+ * Plugins for Controlling Identity Selection and Credential Acquisition
+ *
+ * In order to acquire credentials, Kerberos needs to obtain one or more secrets from the user.
+ * These secrets may be a certificate, password, SecurID pin, or information from a smart card.
+ * If obtaining the secret requires interaction with the user, the Kerberos libraries call a
+ * "prompter callback" to display a dialog or command line prompt to request information from
+ * the user. If you want to provide your own custom dialogs or command line prompts,
+ * the KIM APIs provide a plugin mechanism for replacing the default prompt ui with your own.
+ *
* The function table / structure which a KIM ui plugin module must export
* as "kim_ui_0". If the interfaces work correctly, future versions of the
* table will add either more callbacks or more arguments to callbacks, and
@@ -49,9 +70,19 @@ typedef struct kim_ui_plugin_ftable_v0 {
* this ui. */
kim_error (*init) (void **out_context);
+ /* Present UI which allows the user to enter a new identity.
+ * This is typically called when the user selects a "new tickets"
+ * control or menu item from a ticket management utility.
+ * If this UI calls into KIM to get new credentials it may
+ * call auth_prompt below. */
+ kim_error (*enter_identity) (void *in_context,
+ kim_identity *out_identity);
+
/* Present UI to select which identity to use.
+ * This is typically called the first time an application tries to use
+ * Kerberos and is used to establish a hints preference for the application.
* If this UI calls into KIM to get new credentials it may
- * call acquire_new_credentials below. */
+ * call auth_prompt below. */
kim_error (*select_identity) (void *in_context,
kim_selection_hints in_hints,
kim_identity *out_identity);
@@ -60,13 +91,14 @@ typedef struct kim_ui_plugin_ftable_v0 {
kim_error (*auth_prompt) (void *in_context,
kim_identity in_identity,
kim_prompt_type in_type,
+ kim_boolean in_hide_reply,
kim_string in_title,
kim_string in_message,
kim_string in_description,
char **out_reply);
/* Prompt to change the identity's password.
- * May be combined with an auth prompt if additional auth is required,
+ * May be combined with an auth_prompt if additional auth is required,
* eg: SecurID pin.
* If in_old_password_expired is true, this callback is in response
* to an expired password error. If this is the case the same context
@@ -79,15 +111,18 @@ typedef struct kim_ui_plugin_ftable_v0 {
char **out_verify_password);
/* Display an error to the user; may be called after any of the prompts */
- kim_error (*display_error) (void *in_context,
- kim_identity in_identity,
- kim_error in_error,
- kim_string in_error_message,
- kim_string in_error_description);
+ kim_error (*handle_error) (void *in_context,
+ kim_identity in_identity,
+ kim_error in_error,
+ kim_string in_error_message,
+ kim_string in_error_description);
- /* Free strings returned by the UI */
- void (*free_string) (void *in_context,
- char *io_string);
+ /* Free strings returned by the UI. Will be called once for each string
+ * returned from a plugin callback. If you have returned a string twice
+ * just make sure your free function checks for NULL and sets the pointer
+ * to NULL when done freeing memory. */
+ void (*free_string) (void *in_context,
+ char **io_string);
/* Called after the last prompt (even on error) to allow the UI to
* free allocated resources associated with its context. */
diff --git a/src/kim/lib/kim-lite.exports b/src/kim/lib/kim-lite.exports
index ebad7bf94..1b8466a56 100644
--- a/src/kim/lib/kim-lite.exports
+++ b/src/kim/lib/kim-lite.exports
@@ -16,20 +16,10 @@ kim_identity_get_number_of_components
kim_identity_get_component_at_index
kim_identity_get_krb5_principal
kim_identity_change_password
-kim_identity_change_password_to_password
kim_identity_free
-kim_prompt_callback_default
-kim_prompt_callback_gui
-kim_prompt_callback_cli
-kim_prompt_callback_none
-
kim_options_create
kim_options_copy
-kim_options_set_prompt_callback
-kim_options_get_prompt_callback
-kim_options_set_data
-kim_options_get_data
kim_options_set_start_time
kim_options_get_start_time
kim_options_set_lifetime
@@ -91,6 +81,7 @@ kim_credential_iterator_free
kim_credential_create_new
kim_credential_create_from_krb5_creds
+kim_credential_create_for_change_password
kim_credential_copy
kim_credential_get_krb5_creds
kim_credential_get_client_identity
@@ -103,6 +94,7 @@ kim_credential_get_renewal_expiration_time
kim_credential_store
kim_credential_renew
kim_credential_validate
+kim_credential_change_password
kim_credential_free
kim_ccache_iterator_create
diff --git a/src/kim/lib/kim.exports b/src/kim/lib/kim.exports
index a408815b6..d2f2e27e7 100644
--- a/src/kim/lib/kim.exports
+++ b/src/kim/lib/kim.exports
@@ -16,14 +16,8 @@ kim_identity_get_number_of_components
kim_identity_get_component_at_index
kim_identity_get_krb5_principal
kim_identity_change_password
-kim_identity_change_password_to_password
kim_identity_free
-kim_prompt_callback_default
-kim_prompt_callback_gui
-kim_prompt_callback_cli
-kim_prompt_callback_none
-
kim_options_create
kim_options_copy
kim_options_set_start_time
@@ -88,6 +82,7 @@ kim_credential_iterator_free
kim_credential_create_new
kim_credential_create_from_keytab
kim_credential_create_from_krb5_creds
+kim_credential_create_for_change_password
kim_credential_copy
kim_credential_get_krb5_creds
kim_credential_get_client_identity
@@ -101,6 +96,7 @@ kim_credential_store
kim_credential_verify
kim_credential_renew
kim_credential_validate
+kim_credential_change_password
kim_credential_free
kim_ccache_iterator_create
diff --git a/src/kim/lib/kim_credential.c b/src/kim/lib/kim_credential.c
index 9952a9c72..f81b50f12 100644
--- a/src/kim/lib/kim_credential.c
+++ b/src/kim/lib/kim_credential.c
@@ -179,12 +179,19 @@ static inline kim_error kim_credential_allocate (kim_credential *out_credential)
/* ------------------------------------------------------------------------ */
kim_error kim_credential_create_new (kim_credential *out_credential,
- kim_identity in_client_identity,
+ kim_identity in_identity,
kim_options in_options)
{
kim_error err = KIM_NO_ERROR;
kim_credential credential = NULL;
-
+ kim_options options = NULL;
+ kim_ui_context context;
+ kim_string service = NULL;
+ krb5_principal principal = NULL;
+ krb5_get_init_creds_opt *init_cred_options = NULL;
+ kim_boolean ui_inited = 0;
+ kim_boolean done = 0;
+
if (!err && !out_credential) { err = check_error (KIM_NULL_PARAMETER_ERR); }
if (!err) {
@@ -196,7 +203,82 @@ kim_error kim_credential_create_new (kim_credential *out_credential,
}
if (!err) {
-#warning Get tickets here
+ if (in_options) {
+ options = in_options;
+ } else {
+ err = kim_options_create (&options);
+ }
+ }
+
+ if (!err) {
+ err = kim_options_get_init_cred_options (options,
+ credential->context,
+ &init_cred_options);
+ }
+
+ if (!err) {
+ kim_options_get_service_name (options, &service);
+ }
+
+ if (!err) {
+ err = kim_identity_get_krb5_principal (in_identity,
+ credential->context,
+ &principal);
+ }
+
+ if (!err) {
+ err = kim_ui_init (&context);
+ if (!err) {
+ context.identity = in_identity; /* used by kim_ui_prompter */
+ ui_inited = 1;
+ }
+ }
+
+ while (!err && !done) {
+ krb5_creds creds;
+ kim_boolean free_creds = 0;
+
+ err = krb5_error (credential->context,
+ krb5_get_init_creds_password (credential->context,
+ &creds,
+ principal,
+ NULL,
+ kim_ui_prompter,
+ &context, 0,
+ (char *) service,
+ init_cred_options));
+
+ if (!err) { free_creds = 1; }
+
+ if (!err) {
+ err = krb5_error (credential->context,
+ krb5_copy_creds (credential->context,
+ &creds,
+ &credential->creds));
+ }
+
+ if (!err || err == KIM_USER_CANCELED_ERR) {
+ /* new creds obtained or the user gave up */
+ done = 1;
+
+ } else {
+ /* new creds failed, report error to user */
+ err = kim_ui_handle_kim_error (&context, in_identity,
+ kim_ui_error_type_authentication,
+ err);
+ }
+
+ if (free_creds) { krb5_free_cred_contents (credential->context, &creds); }
+ }
+
+ if (ui_inited) {
+ kim_error fini_err = kim_ui_fini (&context);
+ if (!err) { err = check_error (fini_err); }
+ }
+
+ /* free before credential is passed back to caller */
+ if (credential && init_cred_options) {
+ kim_options_free_init_cred_options (credential->context, &init_cred_options);
}
if (!err) {
@@ -204,6 +286,9 @@ kim_error kim_credential_create_new (kim_credential *out_credential,
credential = NULL;
}
+ if (principal ) { krb5_free_principal (credential->context, principal); }
+ if (!in_options) { kim_options_free (&options); }
+ kim_string_free (&service);
kim_credential_free (&credential);
return check_error (err);
@@ -362,7 +447,9 @@ kim_error kim_credential_create_from_krb5_creds (kim_credential *out_credential,
}
if (!err) {
- err = krb5_error (NULL, krb5_init_context (&credential->context));
+ err = krb5_error (in_krb5_context,
+ krb5_copy_context (in_krb5_context,
+ &credential->context));
}
if (!err) {
@@ -382,6 +469,117 @@ kim_error kim_credential_create_from_krb5_creds (kim_credential *out_credential,
/* ------------------------------------------------------------------------ */
+kim_error kim_credential_create_for_change_password (kim_credential *out_credential,
+ kim_identity in_identity,
+ kim_string in_old_password)
+{
+ kim_error err = KIM_NO_ERROR;
+ kim_credential credential = NULL;
+ kim_string realm = NULL;
+ kim_string service = NULL;
+ kim_ui_context context;
+ krb5_principal principal = NULL;
+ kim_string service_format = "kadmin/changepw@%s";
+ kim_boolean ui_inited = 0;
+ kim_boolean done = 0;
+
+ if (!err && !out_credential ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !in_identity ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !in_old_password) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+
+ if (!err) {
+ err = kim_credential_allocate (&credential);
+ }
+
+ if (!err) {
+ err = krb5_error (NULL, krb5_init_context (&credential->context));
+ }
+
+ if (!err) {
+ err = kim_identity_get_krb5_principal (in_identity,
+ credential->context,
+ &principal);
+ }
+
+ if (!err) {
+ err = kim_identity_get_realm (in_identity, &realm);
+ }
+
+ if (!err) {
+ err = kim_string_create_from_format (&service, service_format, realm);
+ }
+
+ if (!err) {
+ err = kim_ui_init (&context);
+ if (!err) {
+ context.identity = in_identity; /* used by kim_ui_prompter */
+ ui_inited = 1;
+ }
+ }
+
+ while (!err && !done) {
+ krb5_creds creds;
+ kim_boolean free_creds = 0;
+ krb5_get_init_creds_opt opts;
+
+ krb5_get_init_creds_opt_init (&opts);
+ krb5_get_init_creds_opt_set_tkt_life (&opts, 5*60);
+ krb5_get_init_creds_opt_set_renew_life (&opts, 0);
+ krb5_get_init_creds_opt_set_forwardable (&opts, 0);
+ krb5_get_init_creds_opt_set_proxiable (&opts, 0);
+
+ err = krb5_error (credential->context,
+ krb5_get_init_creds_password (credential->context,
+ &creds,
+ principal,
+ (char *) in_old_password,
+ kim_ui_prompter,
+ &context, 0, (char *) service,
+ &opts));
+ if (!err) { free_creds = 1; }
+
+ if (!err) {
+ err = krb5_error (credential->context,
+ krb5_copy_creds (credential->context,
+ &creds,
+ &credential->creds));
+ }
+
+ if (!err || err == KIM_USER_CANCELED_ERR) {
+ /* new creds obtained or the user gave up */
+ done = 1;
+
+ } else {
+ /* new creds failed, report error to user */
+ err = kim_ui_handle_kim_error (&context, in_identity,
+ kim_ui_error_type_change_password,
+ err);
+ }
+
+ if (free_creds) { krb5_free_cred_contents (credential->context, &creds); }
+ }
+
+ if (ui_inited) {
+ kim_error fini_err = kim_ui_fini (&context);
+ if (!err) { err = check_error (fini_err); }
+ }
+
+ if (!err) {
+ *out_credential = credential;
+ credential = NULL;
+ }
+
+ if (principal ) { krb5_free_principal (credential->context, principal); }
+
+ kim_string_free (&realm);
+ kim_string_free (&service);
+ kim_credential_free (&credential);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
kim_error kim_credential_copy (kim_credential *out_credential,
kim_credential in_credential)
{
@@ -396,7 +594,9 @@ kim_error kim_credential_copy (kim_credential *out_credential,
}
if (!err) {
- err = krb5_error (NULL, krb5_init_context (&credential->context));
+ err = krb5_error (in_credential->context,
+ krb5_copy_context (in_credential->context,
+ &credential->context));
}
if (!err) {
@@ -690,8 +890,6 @@ kim_error kim_credential_store (kim_credential in_credential,
k5ccache, in_credential->creds));
}
-#warning Call plugins here
-
if (!err && out_ccache) {
err = kim_ccache_create_from_krb5_ccache (out_ccache, context, k5ccache);
}
@@ -966,6 +1164,130 @@ kim_error kim_credential_validate (kim_credential *io_credential,
/* ------------------------------------------------------------------------ */
+kim_error kim_credential_change_password (kim_credential in_credential,
+ kim_identity in_identity,
+ kim_string in_new_password,
+ kim_error *out_rejected_err,
+ kim_string *out_rejected_message,
+ kim_string *out_rejected_description)
+{
+ kim_error err = KIM_NO_ERROR;
+ krb5_principal principal = NULL;
+ int rejected_code = 0;
+ krb5_data message_data;
+ krb5_data description_data;
+
+ if (!err && !in_credential ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !in_new_password ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !out_rejected_err) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ /* out_rejected_message and out_rejected_description may be NULL */
+
+ if (!err) {
+ err = kim_identity_get_krb5_principal (in_identity,
+ in_credential->context,
+ &principal);
+ }
+
+ if (!err) {
+ err = krb5_error (in_credential->context,
+ krb5_principal_compare (in_credential->context,
+ in_credential->creds->client,
+ principal));
+ }
+
+ if (!err) {
+ if (krb5_principal_compare (in_credential->context,
+ in_credential->creds->client,
+ principal)) {
+ /* Same principal, change the password normally */
+ err = krb5_error (in_credential->context,
+ krb5_change_password (in_credential->context,
+ in_credential->creds,
+ (char *) in_new_password,
+ &rejected_code,
+ &message_data,
+ &description_data));
+ } else {
+ /* Different principal, use set change password protocol */
+ err = krb5_error (in_credential->context,
+ krb5_set_password (in_credential->context,
+ in_credential->creds,
+ (char *) in_new_password,
+ principal,
+ &rejected_code,
+ &message_data,
+ &description_data));
+ }
+
+ }
+
+ if (!err && rejected_code) {
+ kim_string rejected_message = NULL;
+ kim_string rejected_description = NULL;
+
+ if (!err) {
+ if (message_data.data && message_data.length > 0) {
+ err = kim_string_create_from_buffer (&rejected_message,
+ message_data.data,
+ message_data.length);
+ } else {
+ err = kim_os_string_create_localized (&rejected_message,
+ "KLStringChangePasswordFailed");
+ }
+ }
+
+ if (!err) {
+ if (description_data.data && description_data.length > 0) {
+ err = kim_string_create_from_buffer (&rejected_description,
+ description_data.data,
+ description_data.length);
+ } else {
+ err = kim_os_string_create_localized (&rejected_description,
+ "KLStringPasswordRejected");
+ }
+ }
+
+ if (!err) {
+ char *c;
+
+ // replace all \n and \r characters with spaces
+ for (c = (char *) rejected_message; *c != '\0'; c++) {
+ if ((*c == '\n') || (*c == '\r')) { *c = ' '; }
+ }
+
+ for (c = (char *) rejected_description; *c != '\0'; c++) {
+ if ((*c == '\n') || (*c == '\r')) { *c = ' '; }
+ }
+ }
+
+ if (!err) {
+ if (out_rejected_message) {
+ *out_rejected_message = rejected_message;
+ rejected_message = NULL;
+ }
+
+ if (out_rejected_description) {
+ *out_rejected_description = rejected_description;
+ rejected_description = NULL;
+ }
+ }
+
+ kim_string_free (&rejected_message);
+ kim_string_free (&rejected_description);
+
+ krb5_free_data_contents (in_credential->context, &message_data);
+ krb5_free_data_contents (in_credential->context, &description_data);
+ }
+
+ if (!err) {
+ *out_rejected_err = rejected_code;
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
void kim_credential_free (kim_credential *io_credential)
{
if (io_credential && *io_credential) {
diff --git a/src/kim/lib/kim_identity.c b/src/kim/lib/kim_identity.c
index e427a2a1b..7a5b68a9f 100644
--- a/src/kim/lib/kim_identity.c
+++ b/src/kim/lib/kim_identity.c
@@ -92,10 +92,6 @@ kim_error kim_identity_create_from_string (kim_identity *out_identity,
}
if (!err) {
-#warning Run translator here
- }
-
- if (!err) {
*out_identity = identity;
identity = NULL;
}
@@ -175,10 +171,6 @@ kim_error kim_identity_create_from_components (kim_identity *out_identity,
}
if (!err) {
-#warning Run translator here
- }
-
- if (!err) {
*out_identity = identity;
identity = NULL;
}
@@ -226,10 +218,6 @@ kim_error kim_identity_create_from_krb5_principal (kim_identity *out_identity,
}
if (!err) {
-#warning Run translator here
- }
-
- if (!err) {
*out_identity = identity;
identity = NULL;
}
@@ -253,7 +241,9 @@ kim_error kim_identity_copy (kim_identity *out_identity,
err = kim_identity_allocate (&identity);
if (!err) {
- err = krb5_error (NULL, krb5_init_context (&identity->context));
+ err = krb5_error (in_identity->context,
+ krb5_copy_context (in_identity->context,
+ &identity->context));
}
if (!err) {
@@ -546,33 +536,97 @@ kim_error kim_identity_is_tgt_service (kim_identity in_identity,
/* ------------------------------------------------------------------------ */
-kim_error kim_identity_change_password (kim_identity in_identity,
- kim_options in_options)
+kim_error kim_identity_change_password (kim_identity in_identity)
{
kim_error err = KIM_NO_ERROR;
+ kim_ui_context context;
+ kim_boolean ui_inited = 0;
+ kim_boolean done = 0;
if (!err && !in_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
if (!err) {
-#warning Implement change password GUI support
+ err = kim_ui_init (&context);
+ if (!err) { ui_inited = 1; }
}
-
- return check_error (err);
-}
-
-/* ------------------------------------------------------------------------ */
-
-kim_error kim_identity_change_password_to_password (kim_identity in_identity,
- kim_options in_options,
- kim_string in_new_password)
-{
- kim_error err = KIM_NO_ERROR;
- if (!err && !in_identity ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
- if (!err && !in_new_password) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ while (!err && !done) {
+ char *old_password = NULL;
+ char *new_password = NULL;
+ char *verify_password = NULL;
+ kim_error rejected_err = KIM_NO_ERROR;
+ kim_string rejected_message = NULL;
+ kim_string rejected_description = NULL;
+
+ err = kim_ui_change_password (&context,
+ in_identity,
+ 0 /* old password not expired */,
+ &old_password,
+ &new_password,
+ &verify_password);
+
+ if (!err) {
+ kim_comparison comparison;
+
+ err = kim_string_compare (new_password, verify_password, &comparison);
+ if (!err && !kim_comparison_is_equal_to (comparison)) {
+ err = check_error (KIM_PASSWORD_MISMATCH_ERR);
+ }
+ }
+
+ if (!err) {
+ kim_credential credential = NULL;
+
+ if (context.type == kim_ui_type_cli && context.tcontext) {
+ /* command line has already gotten the credentials for us */
+ credential = (kim_credential) context.tcontext;
+ } else {
+ err = kim_credential_create_for_change_password (&credential,
+ in_identity,
+ old_password);
+ }
+
+ if (!err) {
+ err = kim_credential_change_password (credential,
+ in_identity,
+ new_password,
+ &rejected_err,
+ &rejected_message,
+ &rejected_description);
+
+ }
+
+ kim_credential_free (&credential);
+ }
+
+ if (!err || err == KIM_USER_CANCELED_ERR) {
+ /* password change succeeded or the user gave up */
+ done = 1;
+
+ } else if (!err && rejected_err) {
+ /* Password rejected, report it to the user */
+ err = kim_ui_handle_error (&context, in_identity,
+ rejected_err,
+ rejected_message,
+ rejected_description);
+
+ } else {
+ /* Password change failed, report error to user */
+ err = kim_ui_handle_kim_error (&context, in_identity,
+ kim_ui_error_type_change_password,
+ err);
+ }
+
+ kim_string_free (&rejected_message);
+ kim_string_free (&rejected_description);
+ kim_ui_free_string (&context, &old_password);
+ kim_ui_free_string (&context, &new_password);
+ kim_ui_free_string (&context, &verify_password);
+ }
- if (!err) {
-#warning Implement change password support
+ if (ui_inited) {
+ kim_error fini_err = kim_ui_fini (&context);
+ if (!err) { err = check_error (fini_err); }
}
return check_error (err);
diff --git a/src/kim/lib/kim_options.c b/src/kim/lib/kim_options.c
index dbb024c2d..102fa9644 100644
--- a/src/kim/lib/kim_options.c
+++ b/src/kim/lib/kim_options.c
@@ -29,8 +29,6 @@
/* ------------------------------------------------------------------------ */
struct kim_options_opaque {
- kim_prompt_callback prompt_callback;
- const void *prompt_callback_data;
kim_time start_time;
kim_lifetime lifetime;
kim_boolean renewable;
@@ -42,7 +40,6 @@ struct kim_options_opaque {
};
struct kim_options_opaque kim_options_initializer = {
-NULL, NULL,
0,
kim_default_lifetime,
kim_default_renewable,
@@ -121,11 +118,6 @@ kim_error kim_options_copy (kim_options *out_options,
err = kim_options_allocate (&options);
if (!err) {
- options->prompt_callback = in_options->prompt_callback;
- options->prompt_callback_data = in_options->prompt_callback_data;
- }
-
- if (!err) {
options->start_time = in_options->start_time;
options->lifetime = in_options->lifetime;
options->renewable = in_options->renewable;
@@ -153,73 +145,6 @@ kim_error kim_options_copy (kim_options *out_options,
/* ------------------------------------------------------------------------ */
-kim_error kim_options_set_prompt_callback (kim_options io_options,
- kim_prompt_callback in_prompt_callback)
-{
- kim_error err = KIM_NO_ERROR;
-
- if (!err && !io_options) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-
- if (!err) {
- io_options->prompt_callback = in_prompt_callback;
- }
-
- return check_error (err);
-}
-
-/* ------------------------------------------------------------------------ */
-
-kim_error kim_options_get_prompt_callback (kim_options in_options,
- kim_prompt_callback *out_prompt_callback)
-{
- kim_error err = KIM_NO_ERROR;
-
- if (!err && !in_options ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
- if (!err && !out_prompt_callback) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-
- if (!err) {
- *out_prompt_callback = in_options->prompt_callback;
- }
-
- return check_error (err);
-}
-
-/* ------------------------------------------------------------------------ */
-
-kim_error kim_options_set_data (kim_options io_options,
- const void *in_data)
-
-{
- kim_error err = KIM_NO_ERROR;
-
- if (!err && !io_options) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-
- if (!err) {
- io_options->prompt_callback_data = in_data;
- }
-
- return check_error (err);
-}
-
-/* ------------------------------------------------------------------------ */
-
-kim_error kim_options_get_data (kim_options in_options,
- const void **out_data)
-{
- kim_error err = KIM_NO_ERROR;
-
- if (!err && !in_options) { err = check_error (KIM_NULL_PARAMETER_ERR); }
- if (!err && !out_data ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-
- if (!err) {
- *out_data = in_options->prompt_callback_data;
- }
-
- return check_error (err);
-}
-
-/* ------------------------------------------------------------------------ */
-
kim_error kim_options_set_start_time (kim_options io_options,
kim_time in_start_time)
{
@@ -507,22 +432,29 @@ kim_error kim_options_get_init_cred_options (kim_options in_option
if (!err && !in_context ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
if (!err && !out_init_cred_options) { err = check_error (KIM_NULL_PARAMETER_ERR); }
- if (!err && !in_options->addressless) {
- err = krb5_error (in_context,
- krb5_os_localaddr (in_context, &addresses));
- }
-
if (!err) {
krb5_get_init_creds_opt_alloc (in_context, &init_cred_options);
- krb5_get_init_creds_opt_set_tkt_life (init_cred_options, in_options->lifetime);
- krb5_get_init_creds_opt_set_renew_life (init_cred_options, in_options->renewable ? in_options->renewal_lifetime : 0);
- krb5_get_init_creds_opt_set_forwardable (init_cred_options, in_options->forwardable);
- krb5_get_init_creds_opt_set_proxiable (init_cred_options, in_options->proxiable);
- krb5_get_init_creds_opt_set_address_list (init_cred_options, addresses);
+ }
+
+ if (!err && in_options) {
+ if (!in_options->addressless) {
+ err = krb5_error (in_context,
+ krb5_os_localaddr (in_context, &addresses));
+ }
- *out_init_cred_options = init_cred_options;
- init_cred_options = NULL;
- addresses = NULL;
+ if (!err) {
+ krb5_get_init_creds_opt_set_tkt_life (init_cred_options, in_options->lifetime);
+ krb5_get_init_creds_opt_set_renew_life (init_cred_options, in_options->renewable ? in_options->renewal_lifetime : 0);
+ krb5_get_init_creds_opt_set_forwardable (init_cred_options, in_options->forwardable);
+ krb5_get_init_creds_opt_set_proxiable (init_cred_options, in_options->proxiable);
+ krb5_get_init_creds_opt_set_address_list (init_cred_options, addresses);
+ addresses = NULL;
+ }
+ }
+
+ if (!err) {
+ *out_init_cred_options = init_cred_options;
+ init_cred_options = NULL;
}
if (init_cred_options) { krb5_get_init_creds_opt_free (in_context, init_cred_options); }
@@ -543,6 +475,7 @@ kim_error kim_options_free_init_cred_options (krb5_context in_conte
if (!err && io_init_cred_options && *io_init_cred_options) {
if ((*io_init_cred_options)->address_list) {
krb5_free_addresses (in_context, (*io_init_cred_options)->address_list);
+ (*io_init_cred_options)->address_list = NULL;
}
krb5_get_init_creds_opt_free (in_context, *io_init_cred_options);
*io_init_cred_options = NULL;
@@ -561,70 +494,3 @@ void kim_options_free (kim_options *io_options)
*io_options = NULL;
}
}
-
-#pragma mark -
-
-/* ------------------------------------------------------------------------ */
-
-kim_error kim_prompt_callback_default (kim_prompt_type in_type,
- kim_string in_title,
- kim_string in_message,
- kim_string in_description,
- char **out_reply)
-{
- kim_error err = KIM_NO_ERROR;
-
- if (!err && !out_reply) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-
- if (!err) {
- }
-
- return check_error (err);
-}
-
-/* ------------------------------------------------------------------------ */
-
-kim_error kim_prompt_callback_gui (kim_prompt_type in_type,
- kim_string in_title,
- kim_string in_message,
- kim_string in_description,
- char **out_reply)
-{
- kim_error err = KIM_NO_ERROR;
-
- if (!err && !out_reply) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-
- if (!err) {
- }
-
- return check_error (err);
-}
-
-/* ------------------------------------------------------------------------ */
-
-kim_error kim_prompt_callback_cli (kim_prompt_type in_type,
- kim_string in_title,
- kim_string in_message,
- kim_string in_description,
- char **out_reply)
-{
- kim_error err = KIM_NO_ERROR;
-
- if (!err && !out_reply) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-
- if (!err) {
- }
-
- return check_error (err);
-}
-
-/* ------------------------------------------------------------------------ */
-
-kim_error kim_prompt_callback_none (kim_prompt_type in_type,
- kim_string in_title,
- kim_string in_message,
- kim_string in_description,
- char **out_reply)
-{
- return KIM_USER_CANCELED_ERR;
-}
diff --git a/src/kim/lib/kim_selection_hints.c b/src/kim/lib/kim_selection_hints.c
index 78a4c03e8..1aa8555d8 100644
--- a/src/kim/lib/kim_selection_hints.c
+++ b/src/kim/lib/kim_selection_hints.c
@@ -478,7 +478,19 @@ kim_error kim_selection_hints_get_identity (kim_selection_hints in_selection_hi
}
if (!err && !identity && in_selection_hints->allow_user_interaction) {
-#warning GUI to let user pick identity here
+ kim_ui_context context;
+
+ err = kim_ui_init (&context);
+
+ if (!err) {
+ err = kim_ui_select_identity (&context,
+ in_selection_hints,
+ &identity);
+ }
+
+ if (!err) {
+ err = kim_ui_fini (&context);
+ }
}
if (!err) {
diff --git a/src/kim/lib/kim_string.c b/src/kim/lib/kim_string.c
index 94bdb7a89..6968f19d9 100644
--- a/src/kim/lib/kim_string.c
+++ b/src/kim/lib/kim_string.c
@@ -147,6 +147,7 @@ kim_error kim_string_compare (kim_string in_string,
{
return kim_os_string_compare (in_string,
in_compare_to_string,
+ 0, /* case sensitive */
out_comparison);
}
diff --git a/src/kim/lib/kim_string_private.h b/src/kim/lib/kim_string_private.h
index 8998ac7f3..4b1cc1839 100644
--- a/src/kim/lib/kim_string_private.h
+++ b/src/kim/lib/kim_string_private.h
@@ -55,6 +55,10 @@ kim_error kim_string_append (kim_string *io_string,
/* OS-specific because it should use UTF8-safe sorting where possible */
kim_error kim_os_string_compare (kim_string in_string,
kim_string in_compare_to_string,
+ kim_boolean in_case_insensitive,
kim_comparison *out_comparison);
+kim_error kim_os_string_create_localized (kim_string *out_string,
+ kim_string in_string);
+
#endif /* KIM_STRING_PRIVATE_H */
diff --git a/src/kim/lib/kim_ui.c b/src/kim/lib/kim_ui.c
index 1ef364771..36920144e 100644
--- a/src/kim/lib/kim_ui.c
+++ b/src/kim/lib/kim_ui.c
@@ -29,6 +29,78 @@
/* ------------------------------------------------------------------------ */
+static kim_prompt_type kim_ui_ptype2ktype (krb5_prompt_type type)
+{
+ switch (type) {
+ case KRB5_PROMPT_TYPE_PASSWORD:
+ return kim_prompt_type_password;
+
+ case KRB5_PROMPT_TYPE_PREAUTH:
+ return kim_prompt_type_preauth;
+ }
+ return kim_prompt_type_preauth;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Set the identity field in your context and pass the context as the data */
+
+krb5_error_code kim_ui_prompter (krb5_context in_krb5_context,
+ void *in_context,
+ const char *in_name,
+ const char *in_banner,
+ int in_num_prompts,
+ krb5_prompt in_prompts[])
+{
+ kim_error err = KIM_NO_ERROR;
+ krb5_prompt_type *types = NULL;
+ kim_ui_context *context = (kim_ui_context *) in_context;
+ int i;
+
+ if (!err && !in_krb5_context) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !in_context ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !in_prompts ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+
+ if (!err) {
+ types = krb5_get_prompt_types (in_krb5_context);
+ if (!types) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ }
+
+ for (i = 0; !err && i < in_num_prompts; i++) {
+ char *reply = NULL;
+
+ err = kim_ui_auth_prompt (context,
+ context->identity,
+ kim_ui_ptype2ktype (types[i]),
+ in_prompts[i].hidden,
+ in_name,
+ in_banner,
+ in_prompts[i].prompt,
+ &reply);
+
+ if (!err) {
+ uint32_t reply_len = strlen (reply);
+
+ if ((reply_len + 1) > in_prompts[i].reply->length) {
+ kim_debug_printf ("%s(): reply %d is too long (is %d, should be %d)\n",
+ __FUNCTION__, i,
+ reply_len, in_prompts[i].reply->length);
+ reply_len = in_prompts[i].reply->length;
+ }
+
+ memmove (in_prompts[i].reply->data, reply, reply_len + 1);
+ in_prompts[i].reply->length = reply_len;
+ }
+
+ kim_ui_free_string (context, &reply);
+ }
+
+ return check_error (err);
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
kim_error kim_ui_init (kim_ui_context *io_context)
{
kim_error err = KIM_NO_ERROR;
@@ -36,13 +108,15 @@ kim_error kim_ui_init (kim_ui_context *io_context)
if (!err && !io_context) { err = check_error (KIM_NULL_PARAMETER_ERR); }
if (!err) {
+#ifndef LEAN_CLIENT
kim_ui_environment environment = kim_library_ui_environment ();
if (environment == KIM_UI_ENVIRONMENT_GUI) {
+#endif /* LEAN_CLIENT */
io_context->type = kim_ui_type_gui_plugin;
err = kim_ui_plugin_init ((kim_ui_plugin_context *) &io_context->tcontext);
-
+#ifndef LEAN_CLIENT
if (err) {
io_context->type = kim_ui_type_gui_builtin;
@@ -59,6 +133,7 @@ kim_error kim_ui_init (kim_ui_context *io_context)
err = check_error (KIM_NO_UI_ERR);
}
+#endif /* LEAN_CLIENT */
}
return check_error (err);
@@ -66,6 +141,40 @@ kim_error kim_ui_init (kim_ui_context *io_context)
/* ------------------------------------------------------------------------ */
+kim_error kim_ui_enter_identity (kim_ui_context *in_context,
+ kim_identity *out_identity)
+{
+ kim_error err = KIM_NO_ERROR;
+
+ if (!err && !in_context ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !out_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+
+ if (!err) {
+ if (in_context->type == kim_ui_type_gui_plugin) {
+ err = kim_ui_plugin_enter_identity ((kim_ui_plugin_context) in_context->tcontext,
+ out_identity);
+
+#ifndef LEAN_CLIENT
+ } else if (in_context->type == kim_ui_type_gui_builtin) {
+ err = kim_ui_gui_enter_identity ((kim_ui_gui_context) in_context->tcontext,
+ out_identity);
+
+ } else if (in_context->type == kim_ui_type_cli) {
+ err = kim_ui_cli_enter_identity ((kim_ui_cli_context) in_context->tcontext,
+ out_identity);
+
+#endif /* LEAN_CLIENT */
+
+ } else {
+ err = check_error (KIM_NO_UI_ERR);
+ }
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
kim_error kim_ui_select_identity (kim_ui_context *in_context,
kim_selection_hints in_hints,
kim_identity *out_identity)
@@ -82,6 +191,7 @@ kim_error kim_ui_select_identity (kim_ui_context *in_context,
in_hints,
out_identity);
+#ifndef LEAN_CLIENT
} else if (in_context->type == kim_ui_type_gui_builtin) {
err = kim_ui_gui_select_identity ((kim_ui_gui_context) in_context->tcontext,
in_hints,
@@ -92,6 +202,8 @@ kim_error kim_ui_select_identity (kim_ui_context *in_context,
in_hints,
out_identity);
+#endif /* LEAN_CLIENT */
+
} else {
err = check_error (KIM_NO_UI_ERR);
}
@@ -105,6 +217,7 @@ kim_error kim_ui_select_identity (kim_ui_context *in_context,
kim_error kim_ui_auth_prompt (kim_ui_context *in_context,
kim_identity in_identity,
kim_prompt_type in_type,
+ kim_boolean in_hide_reply,
kim_string in_title,
kim_string in_message,
kim_string in_description,
@@ -122,15 +235,18 @@ kim_error kim_ui_auth_prompt (kim_ui_context *in_context,
err = kim_ui_plugin_auth_prompt ((kim_ui_plugin_context) in_context->tcontext,
in_identity,
in_type,
+ in_hide_reply,
in_title,
in_message,
in_description,
out_reply);
+#ifndef LEAN_CLIENT
} else if (in_context->type == kim_ui_type_gui_builtin) {
err = kim_ui_gui_auth_prompt ((kim_ui_gui_context) in_context->tcontext,
in_identity,
in_type,
+ in_hide_reply,
in_title,
in_message,
in_description,
@@ -140,10 +256,12 @@ kim_error kim_ui_auth_prompt (kim_ui_context *in_context,
err = kim_ui_cli_auth_prompt ((kim_ui_cli_context) in_context->tcontext,
in_identity,
in_type,
+ in_hide_reply,
in_title,
in_message,
in_description,
out_reply);
+#endif /* LEAN_CLIENT */
} else {
err = check_error (KIM_NO_UI_ERR);
@@ -179,6 +297,7 @@ kim_error kim_ui_change_password (kim_ui_context *in_context,
out_new_password,
out_verify_password);
+#ifndef LEAN_CLIENT
} else if (in_context->type == kim_ui_type_gui_builtin) {
err = kim_ui_gui_change_password ((kim_ui_gui_context) in_context->tcontext,
in_identity,
@@ -195,6 +314,8 @@ kim_error kim_ui_change_password (kim_ui_context *in_context,
out_new_password,
out_verify_password);
+#endif /* LEAN_CLIENT */
+
} else {
err = check_error (KIM_NO_UI_ERR);
}
@@ -204,12 +325,64 @@ kim_error kim_ui_change_password (kim_ui_context *in_context,
}
/* ------------------------------------------------------------------------ */
+/* Helper function */
+
+kim_error kim_ui_handle_kim_error (kim_ui_context *in_context,
+ kim_identity in_identity,
+ enum kim_ui_error_type in_type,
+ kim_error in_error)
+{
+ kim_error err = KIM_NO_ERROR;
+ kim_string message = NULL;
+ kim_string description = NULL;
+
+ if (!err) {
+ /* Do this first so last error doesn't get overwritten */
+ err = kim_string_get_last_error_message (&description, in_error);
+ }
+
+ if (!err && !in_context) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+
+ if (!err) {
+ kim_string key = NULL;
+
+ switch (in_type) {
+ case kim_ui_error_type_authentication:
+ key = "KLStringLoginFailed";
+ break;
+
+ case kim_ui_error_type_change_password:
+ key = "KLStringChangePasswordFailed";
+ break;
+
+ case kim_ui_error_type_selection:
+ case kim_ui_error_type_generic:
+ default:
+ key = "KLStringKerberosOperationFailed";
+ break;
+ }
+
+ err = kim_os_string_create_localized (&message, key);
+ }
+
+ if (!err) {
+ err = kim_ui_handle_error (in_context, in_identity,
+ in_error, message, description);
+ }
+
+ kim_string_free (&description);
+ kim_string_free (&message);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
-kim_error kim_ui_display_error (kim_ui_context *in_context,
- kim_identity in_identity,
- kim_error in_error,
- kim_string in_error_message,
- kim_string in_error_description)
+kim_error kim_ui_handle_error (kim_ui_context *in_context,
+ kim_identity in_identity,
+ kim_error in_error,
+ kim_string in_error_message,
+ kim_string in_error_description)
{
kim_error err = KIM_NO_ERROR;
@@ -219,25 +392,27 @@ kim_error kim_ui_display_error (kim_ui_context *in_context,
if (!err) {
if (in_context->type == kim_ui_type_gui_plugin) {
- err = kim_ui_plugin_display_error ((kim_ui_plugin_context) in_context->tcontext,
+ err = kim_ui_plugin_handle_error ((kim_ui_plugin_context) in_context->tcontext,
in_identity,
in_error,
in_error_message,
in_error_description);
+#ifndef LEAN_CLIENT
} else if (in_context->type == kim_ui_type_gui_builtin) {
- err = kim_ui_gui_display_error ((kim_ui_gui_context) in_context->tcontext,
+ err = kim_ui_gui_handle_error ((kim_ui_gui_context) in_context->tcontext,
in_identity,
in_error,
in_error_message,
in_error_description);
} else if (in_context->type == kim_ui_type_cli) {
- err = kim_ui_cli_display_error ((kim_ui_cli_context) in_context->tcontext,
+ err = kim_ui_cli_handle_error ((kim_ui_cli_context) in_context->tcontext,
in_identity,
in_error,
in_error_message,
in_error_description);
+#endif /* LEAN_CLIENT */
} else {
err = check_error (KIM_NO_UI_ERR);
@@ -249,19 +424,15 @@ kim_error kim_ui_display_error (kim_ui_context *in_context,
/* ------------------------------------------------------------------------ */
-void kim_ui_free_string (kim_ui_context *in_context,
- char *io_string)
+void kim_ui_free_string (kim_ui_context *in_context,
+ char **io_string)
{
- kim_error err = KIM_NO_ERROR;
-
- if (!err && !in_context) { err = check_error (KIM_NULL_PARAMETER_ERR); }
- if (!err && !io_string ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-
- if (!err) {
+ if (in_context && io_string && *io_string) {
if (in_context->type == kim_ui_type_gui_plugin) {
kim_ui_plugin_free_string ((kim_ui_plugin_context) in_context->tcontext,
io_string);
+#ifndef LEAN_CLIENT
} else if (in_context->type == kim_ui_type_gui_builtin) {
kim_ui_gui_free_string ((kim_ui_gui_context) in_context->tcontext,
io_string);
@@ -269,9 +440,8 @@ void kim_ui_free_string (kim_ui_context *in_context,
} else if (in_context->type == kim_ui_type_cli) {
kim_ui_cli_free_string ((kim_ui_cli_context) in_context->tcontext,
io_string);
+#endif /* LEAN_CLIENT */
- } else {
- err = check_error (KIM_NO_UI_ERR);
}
}
}
@@ -285,14 +455,18 @@ kim_error kim_ui_fini (kim_ui_context *io_context)
if (!err && !io_context) { err = check_error (KIM_NULL_PARAMETER_ERR); }
if (!err) {
+ kim_identity_free (&io_context->identity);
+
if (io_context->type == kim_ui_type_gui_plugin) {
err = kim_ui_plugin_fini ((kim_ui_plugin_context *) &io_context->tcontext);
+#ifndef LEAN_CLIENT
} else if (io_context->type == kim_ui_type_gui_builtin) {
err = kim_ui_gui_fini ((kim_ui_gui_context *) &io_context->tcontext);
} else if (io_context->type == kim_ui_type_cli) {
err = kim_ui_cli_fini ((kim_ui_cli_context *) &io_context->tcontext);
+#endif /* LEAN_CLIENT */
} else {
err = check_error (KIM_NO_UI_ERR);
diff --git a/src/kim/lib/kim_ui_cli.c b/src/kim/lib/kim_ui_cli.c
index d4ba76f58..898b58086 100644
--- a/src/kim/lib/kim_ui_cli.c
+++ b/src/kim/lib/kim_ui_cli.c
@@ -24,19 +24,112 @@
* or implied warranty.
*/
+#ifndef LEAN_CLIENT
+
#include "kim_private.h"
+// ---------------------------------------------------------------------------
+static kim_error kim_ui_cli_read_string (kim_string *out_string,
+ kim_boolean in_hide_reply,
+ const char *in_format, ...)
+{
+ kim_error err = KIM_NO_ERROR;
+ krb5_context k5context = NULL;
+ krb5_prompt prompts[1];
+ char prompt_string [BUFSIZ];
+ krb5_data reply_data;
+ char reply_string [BUFSIZ];
+
+ if (!err && !out_string) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !in_format ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+
+ if (!err) {
+ err = krb5_init_context (&k5context);
+ }
+
+ if (!err) {
+ unsigned int count;
+ va_list args;
+
+ va_start (args, in_format);
+ count = vsnprintf (prompt_string, sizeof (prompt_string),
+ in_format, args);
+ va_end (args);
+
+ if (count > sizeof (prompt_string)) {
+ kim_debug_printf ("%s(): WARNING! Prompt should be %d characters\n",
+ __FUNCTION__, count);
+ prompt_string [sizeof (prompt_string) - 1] = '\0';
+ }
+ }
+
+ if (!err) {
+ /* Build the prompt structures */
+ prompts[0].prompt = prompt_string;
+ prompts[0].hidden = in_hide_reply;
+ prompts[0].reply = &reply_data;
+ prompts[0].reply->data = reply_string;
+ prompts[0].reply->length = sizeof (reply_string);
+
+ err = krb5_prompter_posix (k5context, NULL, NULL, NULL, 1, prompts);
+ if (err == KRB5_LIBOS_PWDINTR) { err = check_error (KIM_USER_CANCELED_ERR); }
+ }
+
+ if (!err) {
+ err = kim_string_create_from_buffer (out_string,
+ prompts[0].reply->data,
+ prompts[0].reply->length);
+ }
+
+ if (k5context) { krb5_free_context (k5context); }
+
+ return check_error (err);
+}
/* ------------------------------------------------------------------------ */
kim_error kim_ui_cli_init (kim_ui_cli_context *out_context)
{
+ *out_context = NULL;
+
return KIM_NO_ERROR;
}
/* ------------------------------------------------------------------------ */
+kim_error kim_ui_cli_enter_identity (kim_ui_cli_context in_context,
+ kim_identity *out_identity)
+{
+ kim_error err = KIM_NO_ERROR;
+ kim_string enter_identity_string = NULL;
+ kim_string identity_string = NULL;
+
+ if (!err && !in_context ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !out_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+
+ if (!err) {
+ err = kim_os_string_create_localized (&enter_identity_string,
+ "KLStringEnterPrincipal");
+ }
+
+ if (!err) {
+ err = kim_ui_cli_read_string (&identity_string,
+ 0, enter_identity_string);
+ }
+
+ if (!err) {
+ err = kim_identity_create_from_string (out_identity, identity_string);
+ }
+
+ kim_string_free (&identity_string);
+ kim_string_free (&enter_identity_string);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
kim_error kim_ui_cli_select_identity (kim_ui_cli_context in_context,
kim_selection_hints in_hints,
kim_identity *out_identity)
@@ -48,6 +141,7 @@ kim_error kim_ui_cli_select_identity (kim_ui_cli_context in_context,
if (!err && !out_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
if (!err) {
+ err = kim_ui_cli_enter_identity (in_context, out_identity);
}
return check_error (err);
@@ -58,6 +152,7 @@ kim_error kim_ui_cli_select_identity (kim_ui_cli_context in_context,
kim_error kim_ui_cli_auth_prompt (kim_ui_cli_context in_context,
kim_identity in_identity,
kim_prompt_type in_type,
+ kim_boolean in_hide_reply,
kim_string in_title,
kim_string in_message,
kim_string in_description,
@@ -71,6 +166,55 @@ kim_error kim_ui_cli_auth_prompt (kim_ui_cli_context in_context,
/* in_title, in_message or in_description may be NULL */
if (!err) {
+ if (in_type == kim_prompt_type_password) {
+ kim_string enter_password_format = NULL;
+ kim_string identity_string = NULL;
+
+ err = kim_os_string_create_localized (&enter_password_format,
+ "KLStringEnterPassword");
+
+ if (!err) {
+ err = kim_identity_get_display_string (in_identity,
+ &identity_string);
+ }
+
+ if (!err) {
+ err = kim_ui_cli_read_string ((kim_string *) out_reply,
+ 1, enter_password_format,
+ identity_string);
+ }
+
+ kim_string_free (&identity_string);
+ kim_string_free (&enter_password_format);
+
+ } else {
+ krb5_context k5context = NULL;
+ krb5_prompt prompts[1];
+ krb5_data reply_data;
+ char reply_string [BUFSIZ];
+
+ prompts[0].prompt = (char *) in_description;
+ prompts[0].hidden = in_hide_reply;
+ prompts[0].reply = &reply_data;
+ prompts[0].reply->data = reply_string;
+ prompts[0].reply->length = sizeof (reply_string);
+
+ err = krb5_init_context (&k5context);
+
+ if (!err) {
+ err = krb5_prompter_posix (k5context, in_context, in_title,
+ in_message, 1, prompts);
+ if (err == KRB5_LIBOS_PWDINTR) { err = check_error (KIM_USER_CANCELED_ERR); }
+ }
+
+ if (!err) {
+ err = kim_string_create_from_buffer ((kim_string *) out_reply,
+ prompts[0].reply->data,
+ prompts[0].reply->length);
+ }
+
+ if (k5context) { krb5_free_context (k5context); }
+ }
}
return check_error (err);
@@ -78,6 +222,88 @@ kim_error kim_ui_cli_auth_prompt (kim_ui_cli_context in_context,
/* ------------------------------------------------------------------------ */
+static kim_error kim_ui_cli_ask_change_password (kim_string in_identity_string)
+{
+ kim_error err = KIM_NO_ERROR;
+ kim_string ask_change_password = NULL;
+ kim_string answer_options = NULL;
+ kim_string yes = NULL;
+ kim_string no = NULL;
+ kim_string unknown_response = NULL;
+ kim_boolean done = 0;
+ kim_comparison no_comparison, yes_comparison;
+
+ if (!err) {
+ err = kim_os_string_create_localized (&ask_change_password,
+ "KLStringPasswordExpired");
+ }
+
+ if (!err) {
+ err = kim_os_string_create_localized (&answer_options,
+ "KLStringYesOrNoAnswerOptions");
+ }
+
+ if (!err) {
+ err = kim_os_string_create_localized (&yes,
+ "KLStringYes");
+ }
+
+ if (!err) {
+ err = kim_os_string_create_localized (&no,
+ "KLStringNo");
+ }
+
+ if (!err) {
+ err = kim_os_string_create_localized (&unknown_response,
+ "KLStringUnknownResponse");
+ }
+
+ while (!err && !done) {
+ kim_string answer = NULL;
+
+ err = kim_ui_cli_read_string (&answer,
+ 0, "%s %s",
+ ask_change_password, answer_options);
+
+ if (!err) {
+ err = kim_os_string_compare (answer, no,
+ 1 /* case insensitive */,
+ &no_comparison);
+ }
+
+ if (!err && kim_comparison_is_equal_to (no_comparison)) {
+ err = check_error (KIM_USER_CANCELED_ERR);
+ }
+
+ if (!err) {
+ err = kim_os_string_compare (answer, yes,
+ 1 /* case insensitive */,
+ &yes_comparison);
+ }
+
+ if (!err) {
+ if (kim_comparison_is_equal_to (yes_comparison)) {
+ done = 1;
+ } else {
+ fprintf (stdout, unknown_response, answer);
+ fprintf (stdout, "\n");
+ }
+ }
+
+ kim_string_free (&answer);
+ }
+
+ kim_string_free (&ask_change_password);
+ kim_string_free (&answer_options);
+ kim_string_free (&yes);
+ kim_string_free (&no);
+ kim_string_free (&unknown_response);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
kim_error kim_ui_cli_change_password (kim_ui_cli_context in_context,
kim_identity in_identity,
kim_boolean in_old_password_expired,
@@ -86,6 +312,13 @@ kim_error kim_ui_cli_change_password (kim_ui_cli_context in_context,
char **out_verify_password)
{
kim_error err = KIM_NO_ERROR;
+ kim_string enter_old_password_format = NULL;
+ kim_string enter_new_password_format = NULL;
+ kim_string enter_verify_password_format = NULL;
+ kim_string identity_string = NULL;
+ kim_string old_password = NULL;
+ kim_string new_password = NULL;
+ kim_string verify_password = NULL;
if (!err && !in_context ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
if (!err && !in_identity ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
@@ -94,18 +327,79 @@ kim_error kim_ui_cli_change_password (kim_ui_cli_context in_context,
if (!err && !out_verify_password) { err = check_error (KIM_NULL_PARAMETER_ERR); }
if (!err) {
+ err = kim_identity_get_display_string (in_identity, &identity_string);
+ }
+
+ if (!err && in_old_password_expired) {
+ err = kim_ui_cli_ask_change_password (identity_string);
+ }
+
+ if (!err) {
+ err = kim_os_string_create_localized (&enter_old_password_format,
+ "KLStringEnterOldPassword");
+ }
+
+ if (!err) {
+ err = kim_os_string_create_localized (&enter_new_password_format,
+ "KLStringEnterNewPassword");
+ }
+
+ if (!err) {
+ err = kim_os_string_create_localized (&enter_verify_password_format,
+ "KLStringEnterVerifyPassword");
+ }
+
+ if (!err) {
+ err = kim_ui_cli_read_string (&old_password,
+ 1, enter_old_password_format,
+ identity_string);
+ }
+
+ if (!err) {
+ err = kim_credential_create_for_change_password (&in_context,
+ in_identity,
+ old_password);
+ }
+
+ if (!err) {
+ err = kim_ui_cli_read_string (&new_password,
+ 1, enter_new_password_format,
+ identity_string);
+ }
+
+ if (!err) {
+ err = kim_ui_cli_read_string (&verify_password,
+ 1, enter_new_password_format,
+ identity_string);
+ }
+
+ if (!err) {
+ *out_old_password = (char *) old_password;
+ old_password = NULL;
+ *out_new_password = (char *) new_password;
+ new_password = NULL;
+ *out_verify_password = (char *) verify_password;
+ verify_password = NULL;
}
+ kim_string_free (&old_password);
+ kim_string_free (&new_password);
+ kim_string_free (&verify_password);
+ kim_string_free (&identity_string);
+ kim_string_free (&enter_old_password_format);
+ kim_string_free (&enter_new_password_format);
+ kim_string_free (&enter_verify_password_format);
+
return check_error (err);
}
/* ------------------------------------------------------------------------ */
-kim_error kim_ui_cli_display_error (kim_ui_cli_context in_context,
- kim_identity in_identity,
- kim_error in_error,
- kim_string in_error_message,
- kim_string in_error_description)
+kim_error kim_ui_cli_handle_error (kim_ui_cli_context in_context,
+ kim_identity in_identity,
+ kim_error in_error,
+ kim_string in_error_message,
+ kim_string in_error_description)
{
kim_error err = KIM_NO_ERROR;
@@ -114,6 +408,7 @@ kim_error kim_ui_cli_display_error (kim_ui_cli_context in_context,
if (!err && !in_error_description) { err = check_error (KIM_NULL_PARAMETER_ERR); }
if (!err) {
+ fprintf (stdout, "%s: %s\n", in_error_message, in_error_description);
}
return check_error (err);
@@ -121,22 +416,21 @@ kim_error kim_ui_cli_display_error (kim_ui_cli_context in_context,
/* ------------------------------------------------------------------------ */
-void kim_ui_cli_free_string (kim_ui_cli_context in_context,
- char *io_string)
+void kim_ui_cli_free_string (kim_ui_cli_context in_context,
+ char **io_string)
{
- kim_error err = KIM_NO_ERROR;
-
- if (!err && !in_context) { err = check_error (KIM_NULL_PARAMETER_ERR); }
- if (!err && !io_string ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-
- if (!err) {
- kim_string_free ((kim_string *) io_string);
- }
+ kim_string_free ((kim_string *) io_string);
}
/* ------------------------------------------------------------------------ */
kim_error kim_ui_cli_fini (kim_ui_cli_context *io_context)
{
+ if (io_context && *io_context) {
+ kim_credential_free (io_context);
+ }
+
return KIM_NO_ERROR;
}
+
+#endif /* LEAN_CLIENT */
diff --git a/src/kim/lib/kim_ui_cli_private.h b/src/kim/lib/kim_ui_cli_private.h
index cc5ff7f0c..89011aa3a 100644
--- a/src/kim/lib/kim_ui_cli_private.h
+++ b/src/kim/lib/kim_ui_cli_private.h
@@ -27,13 +27,18 @@
#ifndef KIM_UI_CLI_PRIVATE_H
#define KIM_UI_CLI_PRIVATE_H
+#ifndef LEAN_CLIENT
+
#include <kim/kim.h>
-typedef void *kim_ui_cli_context;
+typedef kim_credential kim_ui_cli_context;
kim_error kim_ui_cli_init (kim_ui_cli_context *out_context);
+kim_error kim_ui_cli_enter_identity (kim_ui_cli_context in_context,
+ kim_identity *out_identity);
+
kim_error kim_ui_cli_select_identity (kim_ui_cli_context in_context,
kim_selection_hints in_hints,
kim_identity *out_identity);
@@ -41,6 +46,7 @@ kim_error kim_ui_cli_select_identity (kim_ui_cli_context in_context,
kim_error kim_ui_cli_auth_prompt (kim_ui_cli_context in_context,
kim_identity in_identity,
kim_prompt_type in_type,
+ kim_boolean in_hide_reply,
kim_string in_title,
kim_string in_message,
kim_string in_description,
@@ -53,15 +59,17 @@ kim_error kim_ui_cli_change_password (kim_ui_cli_context in_context,
char **out_new_password,
char **out_verify_password);
-kim_error kim_ui_cli_display_error (kim_ui_cli_context in_context,
- kim_identity in_identity,
- kim_error in_error,
- kim_string in_error_message,
- kim_string in_error_description);
+kim_error kim_ui_cli_handle_error (kim_ui_cli_context in_context,
+ kim_identity in_identity,
+ kim_error in_error,
+ kim_string in_error_message,
+ kim_string in_error_description);
-void kim_ui_cli_free_string (kim_ui_cli_context in_context,
- char *io_string);
+void kim_ui_cli_free_string (kim_ui_cli_context in_context,
+ char **io_string);
kim_error kim_ui_cli_fini (kim_ui_cli_context *io_context);
+#endif /* LEAN_CLIENT */
+
#endif /* KIM_UI_CLI_PRIVATE_H */
diff --git a/src/kim/lib/kim_ui_gui.c b/src/kim/lib/kim_ui_gui.c
index 56d0401fa..9eb41e457 100644
--- a/src/kim/lib/kim_ui_gui.c
+++ b/src/kim/lib/kim_ui_gui.c
@@ -24,6 +24,8 @@
* or implied warranty.
*/
+#ifndef LEAN_CLIENT
+
#include "kim_private.h"
@@ -95,6 +97,22 @@ kim_error kim_ui_gui_init (kim_ui_gui_context *out_context)
/* ------------------------------------------------------------------------ */
+kim_error kim_ui_gui_enter_identity (kim_ui_gui_context in_context,
+ kim_identity *out_identity)
+{
+ kim_error err = KIM_NO_ERROR;
+
+ if (!err && !in_context ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !out_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+
+ if (!err) {
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
kim_error kim_ui_gui_select_identity (kim_ui_gui_context in_context,
kim_selection_hints in_hints,
kim_identity *out_identity)
@@ -116,6 +134,7 @@ kim_error kim_ui_gui_select_identity (kim_ui_gui_context in_context,
kim_error kim_ui_gui_auth_prompt (kim_ui_gui_context in_context,
kim_identity in_identity,
kim_prompt_type in_type,
+ kim_boolean in_hide_reply,
kim_string in_title,
kim_string in_message,
kim_string in_description,
@@ -159,11 +178,11 @@ kim_error kim_ui_gui_change_password (kim_ui_gui_context in_context,
/* ------------------------------------------------------------------------ */
-kim_error kim_ui_gui_display_error (kim_ui_gui_context in_context,
- kim_identity in_identity,
- kim_error in_error,
- kim_string in_error_message,
- kim_string in_error_description)
+kim_error kim_ui_gui_handle_error (kim_ui_gui_context in_context,
+ kim_identity in_identity,
+ kim_error in_error,
+ kim_string in_error_message,
+ kim_string in_error_description)
{
kim_error err = KIM_NO_ERROR;
@@ -179,17 +198,10 @@ kim_error kim_ui_gui_display_error (kim_ui_gui_context in_context,
/* ------------------------------------------------------------------------ */
-void kim_ui_gui_free_string (kim_ui_gui_context in_context,
- char *io_string)
+void kim_ui_gui_free_string (kim_ui_gui_context in_context,
+ char **io_string)
{
- kim_error err = KIM_NO_ERROR;
-
- if (!err && !in_context) { err = check_error (KIM_NULL_PARAMETER_ERR); }
- if (!err && !io_string ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
-
- if (!err) {
- kim_string_free ((kim_string *) io_string);
- }
+ kim_string_free ((kim_string *) io_string);
}
/* ------------------------------------------------------------------------ */
@@ -210,3 +222,5 @@ kim_error kim_ui_gui_fini (kim_ui_gui_context *io_context)
return check_error (err);
}
+
+#endif /* LEAN_CLIENT */
diff --git a/src/kim/lib/kim_ui_gui_private.h b/src/kim/lib/kim_ui_gui_private.h
index 9ddffb19a..b6d2ebd52 100644
--- a/src/kim/lib/kim_ui_gui_private.h
+++ b/src/kim/lib/kim_ui_gui_private.h
@@ -27,6 +27,8 @@
#ifndef KIM_UI_GUI_PRIVATE_H
#define KIM_UI_GUI_PRIVATE_H
+#ifndef LEAN_CLIENT
+
#include <kim/kim.h>
struct kim_ui_gui_context;
@@ -35,6 +37,9 @@ typedef struct kim_ui_gui_context *kim_ui_gui_context;
kim_error kim_ui_gui_init (kim_ui_gui_context *out_context);
+kim_error kim_ui_gui_enter_identity (kim_ui_gui_context in_context,
+ kim_identity *out_identity);
+
kim_error kim_ui_gui_select_identity (kim_ui_gui_context in_context,
kim_selection_hints in_hints,
kim_identity *out_identity);
@@ -42,6 +47,7 @@ kim_error kim_ui_gui_select_identity (kim_ui_gui_context in_context,
kim_error kim_ui_gui_auth_prompt (kim_ui_gui_context in_context,
kim_identity in_identity,
kim_prompt_type in_type,
+ kim_boolean in_hide_reply,
kim_string in_title,
kim_string in_message,
kim_string in_description,
@@ -54,15 +60,17 @@ kim_error kim_ui_gui_change_password (kim_ui_gui_context in_context,
char **out_new_password,
char **out_verify_password);
-kim_error kim_ui_gui_display_error (kim_ui_gui_context in_context,
+kim_error kim_ui_gui_handle_error (kim_ui_gui_context in_context,
kim_identity in_identity,
kim_error in_error,
kim_string in_error_message,
kim_string in_error_description);
-void kim_ui_gui_free_string (kim_ui_gui_context in_context,
- char *io_string);
+void kim_ui_gui_free_string (kim_ui_gui_context in_context,
+ char **io_string);
kim_error kim_ui_gui_fini (kim_ui_gui_context *io_context);
+#endif /* LEAN_CLIENT */
+
#endif /* KIM_UI_GUI_PRIVATE_H */
diff --git a/src/kim/lib/kim_ui_plugin.c b/src/kim/lib/kim_ui_plugin.c
index 5c5cc26eb..f1b5db923 100644
--- a/src/kim/lib/kim_ui_plugin.c
+++ b/src/kim/lib/kim_ui_plugin.c
@@ -156,6 +156,24 @@ kim_error kim_ui_plugin_init (kim_ui_plugin_context *out_context)
/* ------------------------------------------------------------------------ */
+kim_error kim_ui_plugin_enter_identity (kim_ui_plugin_context in_context,
+ kim_identity *out_identity)
+{
+ kim_error err = KIM_NO_ERROR;
+
+ if (!err && !in_context ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !out_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+
+ if (!err) {
+ err = in_context->ftable->enter_identity (in_context->plugin_context,
+ out_identity);
+ }
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
kim_error kim_ui_plugin_select_identity (kim_ui_plugin_context in_context,
kim_selection_hints in_hints,
kim_identity *out_identity)
@@ -180,6 +198,7 @@ kim_error kim_ui_plugin_select_identity (kim_ui_plugin_context in_context,
kim_error kim_ui_plugin_auth_prompt (kim_ui_plugin_context in_context,
kim_identity in_identity,
kim_prompt_type in_type,
+ kim_boolean in_hide_reply,
kim_string in_title,
kim_string in_message,
kim_string in_description,
@@ -196,6 +215,7 @@ kim_error kim_ui_plugin_auth_prompt (kim_ui_plugin_context in_context,
err = in_context->ftable->auth_prompt (in_context->plugin_context,
in_identity,
in_type,
+ in_hide_reply,
in_title,
in_message,
in_description,
@@ -236,11 +256,11 @@ kim_error kim_ui_plugin_change_password (kim_ui_plugin_context in_context,
/* ------------------------------------------------------------------------ */
-kim_error kim_ui_plugin_display_error (kim_ui_plugin_context in_context,
- kim_identity in_identity,
- kim_error in_error,
- kim_string in_error_message,
- kim_string in_error_description)
+kim_error kim_ui_plugin_handle_error (kim_ui_plugin_context in_context,
+ kim_identity in_identity,
+ kim_error in_error,
+ kim_string in_error_message,
+ kim_string in_error_description)
{
kim_error err = KIM_NO_ERROR;
@@ -249,11 +269,11 @@ kim_error kim_ui_plugin_display_error (kim_ui_plugin_context in_context,
if (!err && !in_error_description) { err = check_error (KIM_NULL_PARAMETER_ERR); }
if (!err) {
- err = in_context->ftable->display_error (in_context->plugin_context,
- in_identity,
- in_error,
- in_error_message,
- in_error_description);
+ err = in_context->ftable->handle_error (in_context->plugin_context,
+ in_identity,
+ in_error,
+ in_error_message,
+ in_error_description);
}
return check_error (err);
@@ -261,8 +281,8 @@ kim_error kim_ui_plugin_display_error (kim_ui_plugin_context in_context,
/* ------------------------------------------------------------------------ */
-void kim_ui_plugin_free_string (kim_ui_plugin_context in_context,
- char *io_string)
+void kim_ui_plugin_free_string (kim_ui_plugin_context in_context,
+ char **io_string)
{
kim_error err = KIM_NO_ERROR;
diff --git a/src/kim/lib/kim_ui_plugin_private.h b/src/kim/lib/kim_ui_plugin_private.h
index b48166516..c39447df0 100644
--- a/src/kim/lib/kim_ui_plugin_private.h
+++ b/src/kim/lib/kim_ui_plugin_private.h
@@ -35,6 +35,9 @@ typedef struct kim_ui_plugin_context *kim_ui_plugin_context;
kim_error kim_ui_plugin_init (kim_ui_plugin_context *out_context);
+kim_error kim_ui_plugin_enter_identity (kim_ui_plugin_context in_context,
+ kim_identity *out_identity);
+
kim_error kim_ui_plugin_select_identity (kim_ui_plugin_context in_context,
kim_selection_hints in_hints,
kim_identity *out_identity);
@@ -42,6 +45,7 @@ kim_error kim_ui_plugin_select_identity (kim_ui_plugin_context in_context,
kim_error kim_ui_plugin_auth_prompt (kim_ui_plugin_context in_context,
kim_identity in_identity,
kim_prompt_type in_type,
+ kim_boolean in_hide_reply,
kim_string in_title,
kim_string in_message,
kim_string in_description,
@@ -54,14 +58,14 @@ kim_error kim_ui_plugin_change_password (kim_ui_plugin_context in_context,
char **out_new_password,
char **out_verify_password);
-kim_error kim_ui_plugin_display_error (kim_ui_plugin_context in_context,
- kim_identity in_identity,
- kim_error in_error,
- kim_string in_error_message,
- kim_string in_error_description);
+kim_error kim_ui_plugin_handle_error (kim_ui_plugin_context in_context,
+ kim_identity in_identity,
+ kim_error in_error,
+ kim_string in_error_message,
+ kim_string in_error_description);
-void kim_ui_plugin_free_string (kim_ui_plugin_context in_context,
- char *io_string);
+void kim_ui_plugin_free_string (kim_ui_plugin_context in_context,
+ char **io_string);
kim_error kim_ui_plugin_fini (kim_ui_plugin_context *io_context);
diff --git a/src/kim/lib/kim_ui_private.h b/src/kim/lib/kim_ui_private.h
index 21183ef2b..817a4b29f 100644
--- a/src/kim/lib/kim_ui_private.h
+++ b/src/kim/lib/kim_ui_private.h
@@ -36,22 +36,41 @@ enum kim_ui_type {
kim_ui_type_none
};
+enum kim_ui_error_type {
+ kim_ui_error_type_authentication,
+ kim_ui_error_type_change_password,
+ kim_ui_error_type_selection,
+ kim_ui_error_type_generic
+};
+
/* declare struct on stack. Deep contents will be freed by kim_ui_fini. */
typedef struct kim_ui_context {
enum kim_ui_type type;
void *tcontext;
+ kim_identity identity;
} kim_ui_context;
+krb5_error_code kim_ui_prompter (krb5_context in_krb5_context,
+ void *in_context,
+ const char *in_name,
+ const char *in_banner,
+ int in_num_prompts,
+ krb5_prompt in_prompts[]);
+
kim_error kim_ui_init (kim_ui_context *io_context);
+kim_error kim_ui_enter_identity (kim_ui_context *in_context,
+ kim_identity *out_identity);
+
kim_error kim_ui_select_identity (kim_ui_context *in_context,
kim_selection_hints in_hints,
- kim_identity *out_identity);
+ kim_identity *out_identity);
kim_error kim_ui_auth_prompt (kim_ui_context *in_context,
kim_identity in_identity,
kim_prompt_type in_type,
+ kim_boolean in_hide_reply,
kim_string in_title,
kim_string in_message,
kim_string in_description,
@@ -64,14 +83,20 @@ kim_error kim_ui_change_password (kim_ui_context *in_context,
char **out_new_password,
char **out_verify_password);
-kim_error kim_ui_display_error (kim_ui_context *in_context,
- kim_identity in_identity,
- kim_error in_error,
- kim_string in_error_message,
- kim_string in_error_description);
+/* Helper function */
+kim_error kim_ui_handle_kim_error (kim_ui_context *in_context,
+ kim_identity in_identity,
+ enum kim_ui_error_type in_type,
+ kim_error in_error);
+
+kim_error kim_ui_handle_error (kim_ui_context *in_context,
+ kim_identity in_identity,
+ kim_error in_error,
+ kim_string in_error_message,
+ kim_string in_error_description);
void kim_ui_free_string (kim_ui_context *in_context,
- char *io_string);
+ char **io_string);
kim_error kim_ui_fini (kim_ui_context *io_context);
diff --git a/src/kim/lib/mac/kim_os_library.c b/src/kim/lib/mac/kim_os_library.c
index 43dd3d5c7..4abe13e20 100644
--- a/src/kim/lib/mac/kim_os_library.c
+++ b/src/kim/lib/mac/kim_os_library.c
@@ -95,6 +95,7 @@ kim_error kim_os_library_unlock_for_bundle_lookup (void)
kim_ui_environment kim_os_library_get_ui_environment (void)
{
+#ifndef LEAN_CLIENT
kipc_session_attributes_t attributes = kipc_session_get_attributes ();
if (attributes & kkipc_session_caller_uses_gui) {
@@ -106,6 +107,7 @@ kim_ui_environment kim_os_library_get_ui_environment (void)
}
kim_debug_printf ("kim_os_library_get_ui_environment(): no way to talk to the user.");
+#endif
return KIM_UI_ENVIRONMENT_NONE;
}
diff --git a/src/kim/lib/mac/kim_os_string.c b/src/kim/lib/mac/kim_os_string.c
index 9cd8e0559..fab5ed8fe 100644
--- a/src/kim/lib/mac/kim_os_string.c
+++ b/src/kim/lib/mac/kim_os_string.c
@@ -33,8 +33,7 @@ static kim_error kim_os_string_for_key_in_bundle (CFBundleRef in_bundle,
CFStringRef in_key,
kim_string *out_string)
{
- kim_error lock_err = kim_os_library_lock_for_bundle_lookup ();
- kim_error err = lock_err;
+ kim_error err = KIM_NO_ERROR;
kim_string string = NULL;
if (!err && !in_bundle ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
@@ -100,9 +99,7 @@ static kim_error kim_os_string_for_key_in_bundle (CFBundleRef in_bundle,
}
kim_string_free (&string);
-
- if (!lock_err) { kim_os_library_unlock_for_bundle_lookup (); }
-
+
return check_error (err);
}
@@ -110,10 +107,40 @@ static kim_error kim_os_string_for_key_in_bundle (CFBundleRef in_bundle,
/* ------------------------------------------------------------------------ */
+kim_error kim_os_string_create_localized (kim_string *out_string,
+ kim_string in_string)
+{
+ kim_error err = KIM_NO_ERROR;
+ kim_string string = NULL;
+
+ if (!err && !out_string) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+ if (!err && !in_string ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
+
+ if (!err) {
+ err = kim_os_string_create_for_key (&string, in_string);
+ }
+
+ if (!err && !string) {
+ err = kim_string_copy (&string, in_string);
+ }
+
+ if (!err) {
+ *out_string = string;
+ string = NULL;
+ }
+
+ kim_string_free (&string);
+
+ return check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
kim_error kim_os_string_create_for_key (kim_string *out_string,
kim_string in_key_string)
{
- kim_error err = KIM_NO_ERROR;
+ kim_error lock_err = kim_os_library_lock_for_bundle_lookup ();
+ kim_error err = lock_err;
CFStringRef key = NULL;
kim_string string = NULL;
@@ -148,6 +175,8 @@ kim_error kim_os_string_create_for_key (kim_string *out_string,
kim_string_free (&string);
if (key) { CFRelease (key); }
+ if (!lock_err) { kim_os_library_unlock_for_bundle_lookup (); }
+
return check_error (err);
}
@@ -222,6 +251,7 @@ kim_error kim_os_string_get_cfstring (kim_string in_string,
kim_error kim_os_string_compare (kim_string in_string,
kim_string in_compare_to_string,
+ kim_boolean in_case_insensitive,
kim_comparison *out_comparison)
{
kim_error err = KIM_NO_ERROR;
@@ -243,8 +273,13 @@ kim_error kim_os_string_compare (kim_string in_string,
}
if (!err) {
+ CFOptionFlags options = (in_case_insensitive ?
+ 1 : kCFCompareCaseInsensitive);
+
/* Returned CFComparisonResult is compatible with kim_comparison_t */
- *out_comparison = CFStringCompare (cfstring, compare_to_cfstring, 0);
+ *out_comparison = CFStringCompare (cfstring,
+ compare_to_cfstring,
+ options);
}
if (cfstring ) { CFRelease (cfstring); }