diff --git a/evolution-data-server-1.11.5-cert-auth-complete.patch b/evolution-data-server-1.11.5-cert-auth-complete.patch new file mode 100644 index 0000000..c35726e --- /dev/null +++ b/evolution-data-server-1.11.5-cert-auth-complete.patch @@ -0,0 +1,1236 @@ +Index: configure.in +=================================================================== +--- configure.in (revision 7790) ++++ configure.in (working copy) +@@ -1252,6 +1252,11 @@ + dnl Flags for the various libraries we build + dnl **************************************** + ++PKG_CHECK_EXISTS([gnome-certauth-0.0],[ ++ gnome_certauth="gnome-certauth-0.0 >= 0.0" ++ AC_DEFINE([HAVE_GNOME_CERTAUTH], [1], [Define if you have gnome-certauth]) ++]) ++ + dnl --- libedataserver and libedataserverui flags + + E_DATA_SERVER_DEPS="libxml-2.0 gobject-2.0 >= $GLIB_REQUIRED libbonobo-2.0 >= $LIBBONOBO_REQUIRED gconf-2.0 $mozilla_nspr" +@@ -1390,7 +1390,7 @@ AC_SUBST(E_DATA_SERVER_UI_LIBS) + + dnl --- evolution-addressbook flags + +-EVOLUTION_ADDRESSBOOK_DEPS="libxml-2.0 libgnome-2.0 gnome-vfs-2.0" ++EVOLUTION_ADDRESSBOOK_DEPS="libxml-2.0 libgnome-2.0 gnome-vfs-2.0 $gnome_certauth" + + EVO_SET_COMPILE_FLAGS(EVOLUTION_ADDRESSBOOK, $EVOLUTION_ADDRESSBOOK_DEPS) + AC_SUBST(EVOLUTION_ADDRESSBOOK_CFLAGS) +@@ -1398,7 +1398,7 @@ AC_SUBST(EVOLUTION_ADDRESSBOOK_LIBS) + + dnl --- evolution-calendar flags + if test "x${enable_calendar}" = "xyes"; then +- EVOLUTION_CALENDAR_DEPS="libxml-2.0 libgnome-2.0 gnome-vfs-2.0" ++ EVOLUTION_CALENDAR_DEPS="libxml-2.0 libgnome-2.0 gnome-vfs-2.0 $gnome_certauth" + + EVO_SET_COMPILE_FLAGS(EVOLUTION_CALENDAR, $EVOLUTION_CALENDAR_DEPS) + AC_SUBST(EVOLUTION_CALENDAR_CFLAGS) +Index: servers/exchange/storage/exchange-account.c +=================================================================== +--- servers/exchange/storage/exchange-account.c (revision 7790) ++++ servers/exchange/storage/exchange-account.c (working copy) +@@ -39,6 +39,9 @@ + #include "e2k-utils.h" + #include "exchange-hierarchy-foreign.h" + ++#include ++#include ++ + /* This is an ugly hack to avoid API break */ + /* Added for get_authtype */ + #include "exchange-esource.h" +@@ -53,11 +56,23 @@ + #include + #include + +-#define d(x) (x) ++#define TRACE(s, ...) d(fprintf (stderr, "%d:%s:%s():%d "s"\n", getpid(), __FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__)) ++#define TRACEMSG(s) TRACE("%s", (s)) ++#define ENTER TRACEMSG("ENTER") ++#define EXIT TRACEMSG("EXIT") ++#define HASLOCK TRACEMSG("HAS LOCK") ++#define ALREADYLOCKED TRACEMSG("ALREADY LOCKED") ++ ++#define d(x) + #define ADS_UF_DONT_EXPIRE_PASSWORD 0x10000 + #define ONE_HUNDRED_NANOSECOND 0.000000100 + #define SECONDS_IN_DAY 86400 + ++typedef struct { ++ E2kCreds creds; ++ ExchangeAccount *account; ++} AccountCreds; ++ + struct _ExchangeAccountPrivate { + E2kContext *ctx; + E2kGlobalCatalog *gc; +@@ -86,6 +101,10 @@ + + GMutex *discover_data_lock; + GList *discover_datas; ++ ++ AccountCreds creds; ++ GMutex *creds_mutex; ++ GSList *creds_list; + }; + + enum { +@@ -229,6 +248,13 @@ + account->priv->fresh_folders = NULL; + } + ++ if (account->priv->creds_mutex) { ++ g_mutex_free (account->priv->creds_mutex); ++ account->priv->creds_mutex = NULL; ++ } ++ g_slist_free (account->priv->creds_list); ++ account->priv->creds_list = NULL; ++ + G_OBJECT_CLASS (parent_class)->dispose (object); + } + +@@ -1169,14 +1195,21 @@ + + g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), FALSE); + +- g_mutex_lock (account->priv->connect_lock); +- if (account->priv->ctx) { +- g_object_unref (account->priv->ctx); +- account->priv->ctx = NULL; ++ ENTER; ++ ++ if (g_mutex_trylock (account->priv->connect_lock)) { ++ HASLOCK; ++ if (account->priv->ctx) { ++ g_object_unref (account->priv->ctx); ++ account->priv->ctx = NULL; ++ } ++ ++ account->priv->account_online = OFFLINE_MODE; ++ g_mutex_unlock (account->priv->connect_lock); ++ } else { ++ ALREADYLOCKED; + } +- +- account->priv->account_online = OFFLINE_MODE; +- g_mutex_unlock (account->priv->connect_lock); ++ EXIT; + return TRUE; + } + +@@ -1195,11 +1228,15 @@ + exchange_account_set_online (ExchangeAccount *account) + { + g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), FALSE); +- +- g_mutex_lock (account->priv->connect_lock); +- account->priv->account_online = ONLINE_MODE; +- g_mutex_unlock (account->priv->connect_lock); +- ++ ENTER; ++ if (g_mutex_trylock (account->priv->connect_lock)) { ++ HASLOCK; ++ account->priv->account_online = ONLINE_MODE; ++ g_mutex_unlock (account->priv->connect_lock); ++ } else { ++ ALREADYLOCKED; ++ } ++ EXIT; + return TRUE; + } + +@@ -1342,6 +1379,117 @@ + return TRUE; + } + ++/* we are just a patsy */ ++static char * ++account_creds_http_auth_method (E2kCreds *ecreds) ++{ ++ AccountCreds *creds = (AccountCreds *)ecreds; ++ ExchangeAccount *account = creds->account; ++ E2kCreds *sub_creds; ++ char *method; ++ ++ g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), NULL); ++ ++ g_mutex_lock (account->priv->creds_mutex); ++ sub_creds = g_slist_nth_data (account->priv->creds_list, 0); ++ method = sub_creds ? sub_creds->http_auth_method (sub_creds) : NULL; ++ g_mutex_unlock (account->priv->creds_mutex); ++ ++ return method; ++} ++ ++static void ++account_creds_http_authenticate (E2kCreds *ecreds, ++ const char *auth_type, const char *auth_realm, ++ char **username, char **password) ++{ ++ AccountCreds *creds = (AccountCreds *)ecreds; ++ ExchangeAccount *account = creds->account; ++ E2kCreds *sub_creds; ++ ++ g_return_if_fail (EXCHANGE_IS_ACCOUNT (account)); ++ ++ g_mutex_lock (account->priv->creds_mutex); ++ sub_creds = g_slist_nth_data (account->priv->creds_list, 0); ++ if (sub_creds) { ++ sub_creds->http_authenticate (sub_creds, auth_type, auth_realm, username, password); ++ } ++ g_mutex_unlock (account->priv->creds_mutex); ++} ++ ++static int ++account_creds_ssl_cert_request (E2kCreds *ecreds, ++ const gnutls_datum_t *req_ca_rdn_der, ++ int nreqs, ++ gnutls_datum_t **cert_der_ret, ++ int *cert_der_ret_length) ++{ ++ AccountCreds *creds = (AccountCreds *)ecreds; ++ ExchangeAccount *account = creds->account; ++ E2kCreds *sub_creds; ++ int ret = 0; ++ ENTER; ++ g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), -1); ++ ++ g_mutex_lock (account->priv->creds_mutex); ++ HASLOCK; ++ sub_creds = g_slist_nth_data (account->priv->creds_list, 0); ++ if (sub_creds) { ++ TRACEMSG("delegating cert request..."); ++ sub_creds->ssl_cert_request (sub_creds, ++ req_ca_rdn_der, nreqs, ++ cert_der_ret, cert_der_ret_length); ++ } ++ g_mutex_unlock (account->priv->creds_mutex); ++ EXIT; ++ return ret; ++} ++ ++static int ++account_creds_ssl_cert_sign (E2kCreds *ecreds, ++ const gnutls_datum_t *cert_der, ++ const gnutls_datum_t *hash_data, ++ gnutls_datum_t *sig_data) ++{ ++ AccountCreds *creds = (AccountCreds *)ecreds; ++ ExchangeAccount *account = creds->account; ++ E2kCreds *sub_creds; ++ int ret = 0; ++ ++ g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), -1); ++ ++ g_mutex_lock (account->priv->creds_mutex); ++ sub_creds = g_slist_nth_data (account->priv->creds_list, 0); ++ if (sub_creds) { ++ ret = sub_creds->ssl_cert_sign (sub_creds, ++ cert_der, ++ hash_data, sig_data); ++ } ++ g_mutex_unlock (account->priv->creds_mutex); ++ ++ return ret; ++} ++ ++void ++exchange_account_add_creds (ExchangeAccount *account, ++ E2kCreds *creds) ++{ ++ g_return_if_fail (EXCHANGE_IS_ACCOUNT (account)); ++ g_mutex_lock (account->priv->creds_mutex); ++ account->priv->creds_list = g_slist_prepend (account->priv->creds_list, creds); ++ g_mutex_unlock (account->priv->creds_mutex); ++} ++ ++void ++exchange_account_remove_creds (ExchangeAccount *account, ++ E2kCreds *creds) ++{ ++ g_return_if_fail (EXCHANGE_IS_ACCOUNT (account)); ++ g_mutex_lock (account->priv->creds_mutex); ++ account->priv->creds_list = g_slist_remove (account->priv->creds_list, creds); ++ g_mutex_unlock (account->priv->creds_mutex); ++} ++ + /** + * exchange_account_connect: + * @account: an #ExchangeAccount +@@ -1370,13 +1518,16 @@ + E2kOperation gcop; + char *user_name = NULL; + ++ ENTER; ++ + *info_result = EXCHANGE_ACCOUNT_UNKNOWN_ERROR; + g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), NULL); + + *info_result = EXCHANGE_ACCOUNT_CONNECT_SUCCESS; +- exchange_account_is_offline (account, &mode); + + g_mutex_lock (account->priv->connect_lock); ++ HASLOCK; ++ exchange_account_is_offline (account, &mode); + + if (mode == UNSUPPORTED_MODE) { + *info_result = EXCHANGE_ACCOUNT_CONNECT_ERROR; +@@ -1394,10 +1545,17 @@ + else { + *info_result = EXCHANGE_ACCOUNT_CONNECT_ERROR; + } ++ EXIT; + return NULL; + } else if (account->priv->ctx) { + g_mutex_unlock (account->priv->connect_lock); ++ EXIT; + return account->priv->ctx; ++ } else if (!pword && !account->priv->creds_list) { ++ g_mutex_unlock (account->priv->connect_lock); ++ *info_result = EXCHANGE_ACCOUNT_PASSWORD_INCORRECT; ++ EXIT; ++ return NULL; + } + + account->priv->connecting = TRUE; +@@ -1409,7 +1567,7 @@ + + ac = e2k_autoconfig_new (account->home_uri, + user_name, +- NULL, ++ pword, + account->priv->auth_pref); + g_free (user_name); + +@@ -1417,15 +1575,10 @@ + account->priv->ad_limit); + + if (!pword) { +- account->priv->connecting = FALSE; +- g_mutex_unlock (account->priv->connect_lock); +- *info_result = EXCHANGE_ACCOUNT_PASSWORD_INCORRECT; +- e2k_autoconfig_free (ac); +- return NULL; ++ TRACEMSG("setting creds..."); ++ e2k_autoconfig_set_creds (ac, &account->priv->creds.creds); + } + +- e2k_autoconfig_set_password (ac, pword); +- + try_connect_again: + account->priv->ctx = e2k_autoconfig_get_context (ac, NULL, &result); + +@@ -1435,12 +1588,14 @@ + account->priv->nt_domain = NULL; + + if (result != E2K_AUTOCONFIG_OK) { ++ TRACE("result was not ok: %d", result); + #ifdef HAVE_KRB5 + if ( is_password_expired (account, ac)) { + *info_result = EXCHANGE_ACCOUNT_PASSWORD_EXPIRED; + account->priv->connecting = FALSE; + g_mutex_unlock (account->priv->connect_lock); + e2k_autoconfig_free (ac); ++ EXIT; + return NULL; + } + #endif +@@ -1451,6 +1606,7 @@ + e2k_autoconfig_free (ac); + account->priv->connecting = FALSE; + g_mutex_unlock (account->priv->connect_lock); ++ EXIT; + return NULL; + + case E2K_AUTOCONFIG_AUTH_ERROR_TRY_DOMAIN: +@@ -1458,6 +1614,7 @@ + e2k_autoconfig_free (ac); + account->priv->connecting = FALSE; + g_mutex_unlock (account->priv->connect_lock); ++ EXIT; + return NULL; + + case E2K_AUTOCONFIG_AUTH_ERROR_TRY_NTLM: +@@ -1515,6 +1672,7 @@ + } + + g_mutex_unlock (account->priv->connect_lock); ++ EXIT; + return NULL; + } + +@@ -1531,6 +1689,7 @@ + account->priv->connecting = FALSE; + *info_result = EXCHANGE_ACCOUNT_UNKNOWN_ERROR; + g_mutex_unlock (account->priv->connect_lock); ++ EXIT; + return NULL; /* FIXME: what error has happened? */ + } + +@@ -1555,6 +1714,7 @@ + g_mutex_unlock (account->priv->connect_lock); + if (nresults) + e2k_results_free (results, nresults); ++ EXIT; + return NULL; /* FIXME: what error has happened? */ + } + +@@ -1600,6 +1760,7 @@ + g_mutex_unlock (account->priv->connect_lock); + if (nresults) + e2k_results_free (results, nresults); ++ EXIT; + return account->priv->ctx; + } + +@@ -2253,6 +2414,14 @@ + + e2k_uri_free (uri); + ++ account->priv->creds.creds.http_auth_method = account_creds_http_auth_method; ++ account->priv->creds.creds.http_authenticate = account_creds_http_authenticate; ++ account->priv->creds.creds.ssl_cert_request = account_creds_ssl_cert_request; ++ account->priv->creds.creds.ssl_cert_sign = account_creds_ssl_cert_sign; ++ account->priv->creds.account = account; ++ ++ account->priv->creds_mutex = g_mutex_new (); ++ + return account; + } + +Index: servers/exchange/storage/exchange-account.h +=================================================================== +--- servers/exchange/storage/exchange-account.h (revision 7790) ++++ servers/exchange/storage/exchange-account.h (working copy) +@@ -93,6 +93,11 @@ + + char *exchange_account_get_authtype (ExchangeAccount *account); + ++void exchange_account_add_creds (ExchangeAccount *acct, ++ E2kCreds *creds); ++void exchange_account_remove_creds (ExchangeAccount *acct, ++ E2kCreds *creds); ++ + E2kContext *exchange_account_connect (ExchangeAccount *acct, + const char *pword, + ExchangeAccountResult *result); +Index: servers/exchange/lib/e2k-context.c +=================================================================== +--- servers/exchange/lib/e2k-context.c (revision 7790) ++++ servers/exchange/lib/e2k-context.c (working copy) +@@ -51,7 +51,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -59,6 +58,15 @@ + #include + #include + ++#define GCA_TRACE(s, ...) d(fprintf (stderr, "%d:%s:%s():%d "s"\n", getpid(), __FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__)) ++#define d(x) ++ ++#define GCA_TRACEMSG(s) GCA_TRACE("%s", (s)) ++#define GCA_ENTER GCA_TRACEMSG("ENTER") ++#define GCA_EXIT GCA_TRACEMSG("EXIT") ++#define GCA_HASLOCK GCA_TRACEMSG("HAS LOCK") ++#define GCA_ALREADYLOCKED GCA_TRACEMSG("ALREADY LOCKED") ++ + #ifdef G_OS_WIN32 + /* The strtok() in Microsoft's C library is MT-safe (not stateless, + * but that is not needed here). +@@ -89,8 +97,8 @@ + static guint signals [LAST_SIGNAL] = { 0 }; + + struct _E2kContextPrivate { +- SoupSession *session, *async_session; +- char *owa_uri, *username, *password; ++ SoupSession *session; ++ char *owa_uri; + time_t last_timestamp; + + /* Notification listener */ +@@ -114,8 +114,18 @@ + char *cookie; + gboolean cookie_verified; + EProxy* proxy; ++ ++ E2kCreds *creds; ++ gboolean free_creds; + }; + ++typedef struct { ++ E2kCreds creds; ++ char *username; ++ char *authmech; ++ char *password; ++} E2kAuthCreds; ++ + /* For operations with progress */ + #define E2K_CONTEXT_MIN_BATCH_SIZE 25 + #define E2K_CONTEXT_MAX_BATCH_SIZE 100 +@@ -144,6 +162,31 @@ + } + + static void ++release_creds (E2kContext *ctx) ++{ ++ E2kAuthCreds *creds; ++ ++ if (!ctx->priv->creds) { ++ return; ++ } ++ ++ if (!ctx->priv->free_creds) { ++ ctx->priv->creds = NULL; ++ return; ++ } ++ ++ creds = (E2kAuthCreds *)ctx->priv->creds; ++ ++ g_free (creds->username); ++ g_free (creds->authmech); ++ g_free (creds->password); ++ ++ g_free (creds); ++ ctx->priv->free_creds = FALSE; ++ ctx->priv->creds = NULL; ++} ++ ++static void + dispose (GObject *object) + { + E2kContext *ctx = E2K_CONTEXT (object); +@@ -151,10 +194,6 @@ + if (ctx->priv) { + if (ctx->priv->owa_uri) + g_free (ctx->priv->owa_uri); +- if (ctx->priv->username) +- g_free (ctx->priv->username); +- if (ctx->priv->password) +- g_free (ctx->priv->password); + + if (ctx->priv->get_local_address_sock) + g_object_unref (ctx->priv->get_local_address_sock); +@@ -237,11 +247,11 @@ + + if (ctx->priv->session) + g_object_unref (ctx->priv->session); +- if (ctx->priv->async_session) +- g_object_unref (ctx->priv->async_session); + + g_free (ctx->priv->cookie); + ++ release_creds (ctx); ++ + if (ctx->priv->proxy) { + g_object_unref (ctx->priv->proxy); + ctx->priv->proxy = NULL; +@@ -340,10 +379,116 @@ + { + E2kContext *ctx = user_data; + +- *username = g_strdup (ctx->priv->username); +- *password = g_strdup (ctx->priv->password); ++ if (ctx->priv->creds && ctx->priv->creds->http_authenticate) { ++ ctx->priv->creds->http_authenticate (ctx->priv->creds, ++ auth_type, auth_realm, ++ username, password); ++ } + } + ++static int ++session_certificate_requested (SoupSession *session, ++ const gnutls_datum_t *req_ca_rdn, ++ int nreqs, ++ gnutls_datum_t **cert_der_ret, ++ int *cert_der_ret_length, ++ gpointer user_data) ++{ ++ E2kContext *ctx = user_data; ++ int ret = 0; ++ GCA_ENTER; ++ g_return_val_if_fail (E2K_IS_CONTEXT (ctx), -1); ++ ++ if (ctx->priv->creds && ctx->priv->creds->ssl_cert_request) { ++ ret = ctx->priv->creds->ssl_cert_request ( ++ ctx->priv->creds, ++ req_ca_rdn, nreqs, ++ cert_der_ret, cert_der_ret_length); ++ } ++ GCA_EXIT; ++ return ret; ++} ++ ++static int ++session_sign_data (SoupSession *session, ++ gnutls_datum_t *cert, ++ const gnutls_datum_t *hash_data, ++ gnutls_datum_t *sig_data, ++ gpointer user_data) ++{ ++ E2kContext *ctx = user_data; ++ int ret = 0; ++ GCA_ENTER; ++ g_return_val_if_fail (E2K_IS_CONTEXT (ctx), -1); ++ ++ if (ctx->priv->creds && ctx->priv->creds->ssl_cert_sign) { ++ ret = ctx->priv->creds->ssl_cert_sign ( ++ ctx->priv->creds, cert, ++ hash_data, sig_data); ++ } ++ GCA_EXIT; ++ return ret; ++} ++ ++void ++e2k_context_set_creds (E2kContext *ctx, ++ E2kCreds *creds) ++{ ++ guint timeout = E2K_SOUP_SESSION_TIMEOUT; ++ char *authmech = NULL; ++ ++ g_return_if_fail (E2K_IS_CONTEXT (ctx)); ++ g_return_if_fail (creds != NULL); ++ ++ /* Destroy the old sessions so we don't reuse old auths */ ++ if (ctx->priv->session) ++ g_object_unref (ctx->priv->session); ++ ++ release_creds (ctx); ++ ctx->priv->creds = creds; ++ ++ /* Set a default timeout value of 30 seconds. ++ FIXME: Make timeout configurable ++ */ ++ if (g_getenv ("SOUP_SESSION_TIMEOUT")) ++ timeout = atoi (g_getenv ("SOUP_SESSION_TIMEOUT")); ++ ++ if (ctx->priv->creds->http_auth_method) { ++ authmech = ctx->priv->creds->http_auth_method (ctx->priv->creds); ++ } ++ ++ ctx->priv->session = soup_session_sync_new_with_options ( ++ SOUP_SESSION_USE_NTLM, !authmech || !strcmp (authmech, "NTLM"), ++ SOUP_SESSION_TIMEOUT, timeout, ++ NULL); ++ g_signal_connect (ctx->priv->session, "authenticate", ++ G_CALLBACK (session_authenticate), ctx); ++ g_signal_connect (ctx->priv->session, "certificate-requested", ++ G_CALLBACK (session_certificate_requested), ctx); ++ g_signal_connect (ctx->priv->session, "sign-data", ++ G_CALLBACK (session_sign_data), ctx); ++ soup_session_add_filter (ctx->priv->session, ++ SOUP_MESSAGE_FILTER (ctx)); ++ g_free (authmech); ++} ++ ++static char * ++auth_creds_http_auth_method (E2kCreds *e2k_creds) ++{ ++ E2kAuthCreds *creds = (E2kAuthCreds *)e2k_creds; ++ return creds->authmech ? g_strdup (creds->authmech) : NULL; ++} ++ ++static void ++auth_creds_http_authenticate (E2kCreds *e2k_creds, ++ const char *auth_type, const char *auth_realm, ++ char **username, char **password) ++{ ++ E2kAuthCreds *creds = (E2kAuthCreds *)e2k_creds; ++ *username = g_strdup (creds->username); ++ *password = g_strdup (creds->password); ++} ++ + /** + * e2k_context_set_auth: + * @ctx: the context +@@ -533,59 +548,34 @@ + const char *domain, const char *authmech, + const char *password) + { +- guint timeout = E2K_SOUP_SESSION_TIMEOUT; +- SoupUri* uri = NULL; ++ E2kAuthCreds *creds; + + g_return_if_fail (E2K_IS_CONTEXT (ctx)); + ++ creds = g_new0 (E2kAuthCreds, 1); + if (username) { +- g_free (ctx->priv->username); + if (domain) { +- ctx->priv->username = +- g_strdup_printf ("%s\\%s", domain, +- username); ++ creds->username = ++ g_strdup_printf ("%s\\%s", domain, username); + } else +- ctx->priv->username = g_strdup (username); ++ creds->username = g_strdup (username); + } + ++ if (authmech) { ++ creds->authmech = g_strdup (authmech); ++ } ++ + if (password) { +- g_free (ctx->priv->password); +- ctx->priv->password = g_strdup (password); ++ creds->password = g_strdup (password); + } + +- /* Destroy the old sessions so we don't reuse old auths */ +- if (ctx->priv->session) +- g_object_unref (ctx->priv->session); +- if (ctx->priv->async_session) +- g_object_unref (ctx->priv->async_session); +- +- /* Set a default timeout value of 30 seconds. +- FIXME: Make timeout configurable +- */ +- if (g_getenv ("SOUP_SESSION_TIMEOUT")) +- timeout = atoi (g_getenv ("SOUP_SESSION_TIMEOUT")); +- +- /* Check do we need a proxy to contact the server? */ +- if (e_proxy_require_proxy_for_uri (ctx->priv->proxy, ctx->priv->owa_uri)) +- uri = e_proxy_peek_uri (ctx->priv->proxy); +- +- ctx->priv->session = soup_session_sync_new_with_options ( +- SOUP_SESSION_USE_NTLM, !authmech || !strcmp (authmech, "NTLM"), +- SOUP_SESSION_TIMEOUT, timeout, +- SOUP_SESSION_PROXY_URI, uri, +- NULL); +- g_signal_connect (ctx->priv->session, "authenticate", +- G_CALLBACK (session_authenticate), ctx); +- soup_session_add_filter (ctx->priv->session, +- SOUP_MESSAGE_FILTER (ctx)); +- +- ctx->priv->async_session = soup_session_async_new_with_options ( +- SOUP_SESSION_USE_NTLM, !authmech || !strcmp (authmech, "NTLM"), +- SOUP_SESSION_PROXY_URI, uri, NULL); +- g_signal_connect (ctx->priv->async_session, "authenticate", +- G_CALLBACK (session_authenticate), ctx); +- soup_session_add_filter (ctx->priv->async_session, +- SOUP_MESSAGE_FILTER (ctx)); ++ creds->creds.http_auth_method = auth_creds_http_auth_method; ++ creds->creds.http_authenticate = auth_creds_http_authenticate; ++ ++ e2k_context_set_creds (ctx, &creds->creds); ++ /* we can't set this before because release_creds would then ++ * free it */ ++ ctx->priv->free_creds = TRUE; + } + + /** +@@ -550,6 +676,8 @@ + SoupMessage *post_msg; + GString *form_body, *cookie_str; + const GSList *cookies, *c; ++ char *username = NULL; ++ char *password = NULL; + + g_return_val_if_fail (E2K_IS_CONTEXT (ctx), FALSE); + +@@ -568,7 +696,7 @@ + /* Otherwise, it's just expired. */ + } + +- if (!ctx->priv->username || !ctx->priv->password) ++ if (!ctx->priv->creds || !ctx->priv->creds->http_authenticate) + return FALSE; + + in_fba_auth = TRUE; +@@ -608,6 +736,15 @@ + action = g_strdup (value); + xmlFree (value); + ++ /* we already checked this above */ ++ ctx->priv->creds->http_authenticate (ctx->priv->creds, ++ "", "", /* fake these... */ ++ &username, &password); ++ ++ if (!username || !password) { ++ goto failed; ++ } ++ + form_body = g_string_new (NULL); + while ((node = e2k_xml_find (node, "input"))) { + name = xmlGetProp (node, "name"); +@@ -626,11 +763,11 @@ + g_string_append_c (form_body, '&'); + } else if (!g_ascii_strcasecmp (name, "username")) { + g_string_append (form_body, "username="); +- e2k_uri_append_encoded (form_body, ctx->priv->username, FALSE, NULL); ++ e2k_uri_append_encoded (form_body, username, FALSE, NULL); + g_string_append_c (form_body, '&'); + } else if (!g_ascii_strcasecmp (name, "password")) { + g_string_append (form_body, "password="); +- e2k_uri_append_encoded (form_body, ctx->priv->password, FALSE, NULL); ++ e2k_uri_append_encoded (form_body, password, FALSE, NULL); + g_string_append_c (form_body, '&'); + } + +@@ -638,6 +775,12 @@ + xmlFree (value); + xmlFree (name); + } ++ g_free (username); ++ username = NULL; ++ ++ g_free (password); ++ password = NULL; ++ + g_string_append_printf (form_body, "trusted=%d", E2K_FBA_FLAG_TRUSTED); + xmlFreeDoc (doc); + doc = NULL; +@@ -687,6 +830,8 @@ + in_fba_auth = FALSE; + if (doc) + xmlFreeDoc (doc); ++ g_free (username); ++ g_free (password); + return FALSE; + } + +@@ -842,7 +987,7 @@ + { + g_return_if_fail (E2K_IS_CONTEXT (ctx)); + +- soup_session_queue_message (ctx->priv->async_session, msg, ++ soup_session_queue_message (ctx->priv->session, msg, + callback, user_data); + } + +--- servers/exchange/lib/e2k-context.c~ 2007-07-31 15:59:43.000000000 -0400 ++++ servers/exchange/lib/e2k-context.c 2007-07-31 16:08:11.000000000 -0400 +@@ -463,6 +473,7 @@ + E2kCreds *creds) + { + guint timeout = E2K_SOUP_SESSION_TIMEOUT; ++ SoupUri* uri = NULL; + char *authmech = NULL; + + g_return_if_fail (E2K_IS_CONTEXT (ctx)); +@@ -481,6 +492,10 @@ + if (g_getenv ("SOUP_SESSION_TIMEOUT")) + timeout = atoi (g_getenv ("SOUP_SESSION_TIMEOUT")); + ++ /* Check do we need a proxy to contact the server? */ ++ if (e_proxy_require_proxy_for_uri (ctx->priv->proxy, ctx->priv->owa_uri)) ++ uri = e_proxy_peek_uri (ctx->priv->proxy); ++ + if (ctx->priv->creds->http_auth_method) { + authmech = ctx->priv->creds->http_auth_method (ctx->priv->creds); + } +@@ -488,6 +503,7 @@ + ctx->priv->session = soup_session_sync_new_with_options ( + SOUP_SESSION_USE_NTLM, !authmech || !strcmp (authmech, "NTLM"), + SOUP_SESSION_TIMEOUT, timeout, ++ SOUP_SESSION_PROXY_URI, uri, + NULL); + g_signal_connect (ctx->priv->session, "authenticate", + G_CALLBACK (session_authenticate), ctx); +Index: servers/exchange/lib/e2k-context.h +=================================================================== +--- servers/exchange/lib/e2k-context.h (revision 7790) ++++ servers/exchange/lib/e2k-context.h (working copy) +@@ -9,6 +9,8 @@ + + #include + ++#include ++ + #include "e2k-types.h" + #include "e2k-operation.h" + #include "e2k-http-utils.h" +@@ -47,6 +49,25 @@ + const char *domain, + const char *authmech, + const char *password); ++struct _E2kCreds { ++ char *(*http_auth_method) (E2kCreds *creds); ++ void (*http_authenticate) (E2kCreds *creds, ++ const char *auth_type, const char *auth_realm, ++ char **username, char **password); ++ int (*ssl_cert_request) (E2kCreds *creds, ++ const gnutls_datum_t *req_ca_rdn_der, ++ int nreqs, ++ gnutls_datum_t **cert_der_ret, ++ int *cert_der_ret_length); ++ int (*ssl_cert_sign) (E2kCreds *creds, ++ const gnutls_datum_t *cert, ++ const gnutls_datum_t *hash_data, ++ gnutls_datum_t *sig_data); ++}; ++ ++void e2k_context_set_creds (E2kContext *ctx, ++ E2kCreds *creds); ++ + gboolean e2k_context_fba (E2kContext *ctx, + SoupMessage *failed_msg); + +Index: servers/exchange/lib/e2k-autoconfig.c +=================================================================== +--- servers/exchange/lib/e2k-autoconfig.c (revision 7790) ++++ servers/exchange/lib/e2k-autoconfig.c (working copy) +@@ -337,6 +337,13 @@ + } + } + ++void ++e2k_autoconfig_set_creds (E2kAutoconfig *ac, ++ E2kCreds *creds) ++{ ++ ac->creds = creds; ++} ++ + /* + * e2k_autoconfig_get_context: + * @ac: an autoconfig context +@@ -395,8 +402,12 @@ + *result = E2K_AUTOCONFIG_FAILED; + return NULL; + } +- e2k_context_set_auth (ctx, ac->username, ac->nt_domain, +- ac->use_ntlm ? "NTLM" : "Basic", ac->password); ++ if (ac->creds) { ++ e2k_context_set_creds (ctx, ac->creds); ++ } else { ++ e2k_context_set_auth (ctx, ac->username, ac->nt_domain, ++ ac->use_ntlm ? "NTLM" : "Basic", ac->password); ++ } + + msg = e2k_soup_message_new (ctx, ac->owa_uri, SOUP_METHOD_GET); + soup_message_add_header (msg->request_headers, "Accept-Language", +Index: servers/exchange/lib/e2k-autoconfig.h +=================================================================== +--- servers/exchange/lib/e2k-autoconfig.h (revision 7790) ++++ servers/exchange/lib/e2k-autoconfig.h (working copy) +@@ -47,6 +47,7 @@ + gboolean require_ntlm, use_ntlm; + gboolean saw_basic, saw_ntlm; + gboolean nt_domain_defaulted, gc_server_autodetected; ++ E2kCreds *creds; + } E2kAutoconfig; + + E2kAutoconfig *e2k_autoconfig_new (const char *owa_uri, +@@ -64,7 +65,8 @@ + const char *username); + void e2k_autoconfig_set_password (E2kAutoconfig *ac, + const char *password); +- ++void e2k_autoconfig_set_creds (E2kAutoconfig *ac, ++ E2kCreds *creds); + E2kContext *e2k_autoconfig_get_context (E2kAutoconfig *ac, + E2kOperation *op, + E2kAutoconfigResult *result); +Index: servers/exchange/lib/e2k-types.h +=================================================================== +--- servers/exchange/lib/e2k-types.h (revision 7790) ++++ servers/exchange/lib/e2k-types.h (working copy) +@@ -14,6 +14,7 @@ + typedef struct _E2kContext E2kContext; + typedef struct _E2kContextPrivate E2kContextPrivate; + typedef struct _E2kContextClass E2kContextClass; ++typedef struct _E2kCreds E2kCreds; + + typedef struct _E2kGlobalCatalog E2kGlobalCatalog; + typedef struct _E2kGlobalCatalogPrivate E2kGlobalCatalogPrivate; +Index: addressbook/libebook/e-book.c +=================================================================== +--- addressbook/libebook/e-book.c (revision 7790) ++++ addressbook/libebook/e-book.c (working copy) +@@ -17,6 +17,10 @@ + #include + #include + ++#ifdef HAVE_GNOME_CERTAUTH ++#include ++#endif ++ + #include "e-book-listener.h" + + #define d(x) +@@ -3277,6 +3281,9 @@ + GError **error) + { + GNOME_Evolution_Addressbook_Book corba_book = CORBA_OBJECT_NIL; ++#ifdef HAVE_GNOME_CERTAUTH ++ GObject *nss_source; ++#endif + gchar *uri; + gchar *source_xml; + GList *factories; +@@ -3293,6 +3300,7 @@ + /* try to find a list of factories that can handle the protocol */ + factories = activate_factories_for_uri (book, uri); + if (!factories) { ++ g_free (uri); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED, + _("%s: no factories available for URI `%s'"), "e_book_load_uri", uri); + return FALSE; +@@ -3304,11 +3312,28 @@ + */ + book->priv->listener = e_book_listener_new (); + if (book->priv->listener == NULL) { ++ g_free (uri); + g_warning ("e_book_load_uri: Could not create EBookListener!\n"); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_OTHER_ERROR, + _("%s: Could not create EBookListener"), "e_book_load_uri"); + return FALSE; + } ++#ifdef HAVE_GNOME_CERTAUTH ++ nss_source = g_object_new (GCA_TYPE_NSS_CERTIFICATE_SOURCE, ++ "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST), ++ NULL); ++ if (!nss_source) { ++ g_object_unref (book->priv->listener); ++ book->priv->listener = NULL; ++ g_free (uri); ++ g_warning ("e_book_load_uri: Could not create GcaNssCertificateSource!\n"); ++ g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_OTHER_ERROR, ++ _("%s: Could not create GcaNssCertificateSource"), "e_book_load_uri"); ++ return FALSE; ++ } ++ bonobo_object_add_interface (BONOBO_OBJECT (book->priv->listener), ++ BONOBO_OBJECT (nss_source)); ++#endif + book->priv->listener_signal = g_signal_connect_object (book->priv->listener, "response", + G_CALLBACK (e_book_handle_response), + book, 0); +Index: addressbook/libedata-book/e-book-backend.c +=================================================================== +--- addressbook/libedata-book/e-book-backend.c (revision 7790) ++++ addressbook/libedata-book/e-book-backend.c (working copy) +@@ -27,6 +27,8 @@ + /* Signal IDs */ + enum { + LAST_CLIENT_GONE, ++ ADD_CLIENT, ++ REMOVE_CLIENT, + LAST_SIGNAL + }; + +@@ -570,6 +572,8 @@ + backend->priv->clients = g_list_prepend (backend->priv->clients, book); + g_mutex_unlock (backend->priv->clients_mutex); + ++ g_signal_emit (backend, e_book_backend_signals[ADD_CLIENT], 0, book); ++ + return TRUE; + } + +@@ -592,6 +596,8 @@ + lock) */ + g_object_ref (backend); + ++ g_signal_emit (backend, e_book_backend_signals[REMOVE_CLIENT], 0, book); ++ + /* Disconnect */ + g_mutex_lock (backend->priv->clients_mutex); + backend->priv->clients = g_list_remove (backend->priv->clients, book); +@@ -1085,6 +1091,24 @@ + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); ++ ++ e_book_backend_signals[ADD_CLIENT] = ++ g_signal_new ("add_client", ++ G_OBJECT_CLASS_TYPE (object_class), ++ G_SIGNAL_RUN_FIRST, ++ G_STRUCT_OFFSET (EBookBackendClass, add_client), ++ NULL, NULL, ++ g_cclosure_marshal_VOID__POINTER, ++ G_TYPE_NONE, 1, G_TYPE_POINTER); ++ ++ e_book_backend_signals[REMOVE_CLIENT] = ++ g_signal_new ("remove_client", ++ G_OBJECT_CLASS_TYPE (object_class), ++ G_SIGNAL_RUN_FIRST, ++ G_STRUCT_OFFSET (EBookBackendClass, remove_client), ++ NULL, NULL, ++ g_cclosure_marshal_VOID__POINTER, ++ G_TYPE_NONE, 1, G_TYPE_POINTER); + } + + /** +Index: addressbook/libedata-book/e-book-backend.h +=================================================================== +--- addressbook/libedata-book/e-book-backend.h (revision 7790) ++++ addressbook/libedata-book/e-book-backend.h (working copy) +@@ -73,9 +73,10 @@ + + void (*sync) (EBookBackend *backend); + ++ void (*add_client) (EBookBackend *backend, EDataBook *book); ++ void (*remove_client) (EBookBackend *backend, EDataBook *book); ++ + /* Padding for future expansion */ +- void (*_pas_reserved1) (void); +- void (*_pas_reserved2) (void); + void (*_pas_reserved3) (void); + void (*_pas_reserved4) (void); + }; +Index: calendar/libedata-cal/e-cal-backend.c +=================================================================== +--- calendar/libedata-cal/e-cal-backend.c (revision 7790) ++++ calendar/libedata-cal/e-cal-backend.c (working copy) +@@ -66,6 +66,8 @@ + LAST_CLIENT_GONE, + OPENED, + REMOVED, ++ ADD_CLIENT, ++ REMOVE_CLIENT, + LAST_SIGNAL + }; + static guint e_cal_backend_signals[LAST_SIGNAL]; +@@ -237,6 +239,22 @@ + G_TYPE_NONE, 1, + G_TYPE_INT); + ++ e_cal_backend_signals[ADD_CLIENT] = ++ g_signal_new ("add_client", ++ G_TYPE_FROM_CLASS (class), ++ G_SIGNAL_RUN_FIRST, ++ 0, NULL, NULL, ++ g_cclosure_marshal_VOID__POINTER, ++ G_TYPE_NONE, 1, G_TYPE_POINTER); ++ ++ e_cal_backend_signals[ADD_CLIENT] = ++ g_signal_new ("remove_client", ++ G_TYPE_FROM_CLASS (class), ++ G_SIGNAL_RUN_FIRST, ++ 0, NULL, NULL, ++ g_cclosure_marshal_VOID__POINTER, ++ G_TYPE_NONE, 1, G_TYPE_POINTER); ++ + class->last_client_gone = NULL; + class->opened = NULL; + class->obj_updated = NULL; +@@ -422,6 +440,8 @@ + g_mutex_lock (priv->clients_mutex); + priv->clients = g_list_append (priv->clients, cal); + g_mutex_unlock (priv->clients_mutex); ++ ++ g_signal_emit (backend, e_cal_backend_signals[ADD_CLIENT], 0, cal); + } + + /** +@@ -446,6 +466,8 @@ + + priv = backend->priv; + ++ g_signal_emit (backend, e_cal_backend_signals[REMOVE_CLIENT], 0, cal); ++ + /* Disconnect */ + g_mutex_lock (priv->clients_mutex); + priv->clients = g_list_remove (priv->clients, cal); +Index: calendar/libecal/e-cal.c +=================================================================== +--- calendar/libecal/e-cal.c (revision 7790) ++++ calendar/libecal/e-cal.c (working copy) +@@ -41,6 +41,9 @@ + #include "e-cal-view-private.h" + #include "e-cal.h" + ++#ifdef HAVE_GNOME_CERTAUTH ++#include ++#endif + + static gboolean + open_calendar (ECal *ecal, gboolean only_if_exists, GError **error, ECalendarStatus *status, gboolean needs_auth); +@@ -987,19 +991,19 @@ + g_mutex_unlock (op->mutex); + } + +-static gboolean ++static gpointer + reopen_with_auth (gpointer data) + { + ECalendarStatus status; + + open_calendar (E_CAL (data), TRUE, NULL, &status, TRUE); +- return FALSE; ++ return NULL; + } + + static void + auth_required_cb (ECalListener *listener, gpointer data) + { +- g_idle_add (reopen_with_auth, data); ++ g_thread_create (reopen_with_auth, data, FALSE, NULL); + + } + +@@ -1141,7 +1145,9 @@ + e_cal_init (ECal *ecal, ECalClass *klass) + { + ECalPrivate *priv; +- ++#ifdef HAVE_GNOME_CERTAUTH ++ GObject *nss_source; ++#endif + priv = g_new0 (ECalPrivate, 1); + ecal->priv = priv; + +@@ -1151,6 +1157,18 @@ + priv->mutex = g_mutex_new (); + priv->listener = e_cal_listener_new (cal_set_mode_cb, ecal); + ++#ifdef HAVE_GNOME_CERTAUTH ++ nss_source = g_object_new (GCA_TYPE_NSS_CERTIFICATE_SOURCE, ++ "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST), ++ NULL); ++ if (!nss_source) { ++ g_warning ("e_cal_init: Could not create GcaNssCertificateSource!\n"); ++ } else { ++ bonobo_object_add_interface (BONOBO_OBJECT (priv->listener), ++ BONOBO_OBJECT (nss_source)); ++ } ++#endif ++ + priv->cal_address = NULL; + priv->alarm_email_address = NULL; + priv->ldap_attribute = NULL; +@@ -1730,7 +1748,7 @@ + g_mutex_unlock (priv->mutex); + + /* see if the backend needs authentication */ +- if ( (priv->mode != CAL_MODE_LOCAL) && e_source_get_property (priv->source, "auth")) { ++ if ( needs_auth && (priv->mode != CAL_MODE_LOCAL) && e_source_get_property (priv->source, "auth")) { + char *prompt, *key; + const char *parent_user; + +--- servers/exchange/lib/e2k-context.c~ 2007-07-31 16:29:07.000000000 -0400 ++++ servers/exchange/lib/e2k-context.c 2007-07-31 16:33:45.000000000 -0400 +@@ -154,9 +154,7 @@ + { + SoupUri *proxy_uri = NULL; + E2kContext* ctx = (E2kContext *)user_data; +- if (!ctx || !ctx->priv || +- (!ctx->priv->session && !ctx->priv->async_session) || +- (!ctx->priv->owa_uri)) ++ if (!ctx || !ctx->priv || !ctx->priv->session || !ctx->priv->owa_uri) + return; + + if (!e_proxy_require_proxy_for_uri (proxy, ctx->priv->owa_uri)) +@@ -167,9 +165,6 @@ + if (ctx->priv->session) + g_object_set (ctx->priv->session, SOUP_SESSION_PROXY_URI, + proxy_uri, NULL); +- if (ctx->priv->async_session) +- g_object_set (ctx->priv->async_session, SOUP_SESSION_PROXY_URI, +- proxy_uri, NULL); + } + + static void diff --git a/evolution-data-server.changes b/evolution-data-server.changes index 14d289c..eff7eeb 100644 --- a/evolution-data-server.changes +++ b/evolution-data-server.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Fri Aug 17 21:57:23 CEST 2007 - jberkman@novell.com + +- add auth support for smartcards (bug #273869) + ------------------------------------------------------------------- Mon Aug 6 20:24:32 CEST 2007 - maw@suse.de diff --git a/evolution-data-server.spec b/evolution-data-server.spec index da11b42..e816c61 100644 --- a/evolution-data-server.spec +++ b/evolution-data-server.spec @@ -11,13 +11,13 @@ # norootforbuild Name: evolution-data-server -BuildRequires: bison db-devel fdupes gcc-c++ gnome-common gnome-keyring-devel gtk-doc intltool krb5-devel libglade2-devel libgnome-devel libidl-devel libsoup-devel mDNSResponder-devel mozilla-nss-devel openldap2 openldap2-devel perl-XML-Parser python-devel sgml-skel +BuildRequires: bison db-devel fdupes gcc-c++ gnome-certauth-devel gnome-common gnome-keyring-devel gtk-doc intltool krb5-devel libglade2-devel libgnome-devel libidl-devel libsoup-devel mDNSResponder-devel mozilla-nss-devel openldap2 openldap2-devel perl-XML-Parser python-devel sgml-skel License: GPL v2 or later Group: Development/Libraries/GNOME Autoreqprov: on Summary: Evolution Data Server Version: 1.11.6.1 -Release: 4 +Release: 9 Source: ftp://ftp.gnome.org/pub/gnome/sources/evolution-data-server/1.11/%{name}-%{version}.tar.bz2 #Patch3: evolution-data-server-gcc4.patch Patch5: evolution-data-server-configure.patch @@ -106,6 +106,7 @@ Patch84: cal-attachment-filename-handling.patch Patch85: bnc-167330-default-GW-alarms.patch Patch86: eds-compiler-warning.patch Patch89: bgo-369168-buffer-overrun.patch +Patch90: evolution-data-server-1.11.5-cert-auth-complete.patch # Change patch below if we move away from /opt/gnome # It avoids a build dependency on libgnomeui to speed up bootstrap Patch99: libgnomeui-dep.patch @@ -126,7 +127,7 @@ Summary: Evolution Data Server Development Files Group: Development/Libraries/GNOME Requires: evolution-data-server = %{?epoch:%{epoch}:}%{version}-%{release} Requires: libsoup-devel libbonobo-devel libgnome-devel gnome-vfs2-devel libxml2-devel orbit2-devel openldap2-devel libglade2-devel -Requires: gtk2-devel gconf2-devel glib2-devel gnome-keyring-devel +Requires: gtk2-devel gconf2-devel glib2-devel gnome-keyring-devel gnome-certauth-devel %if %suse_version >= 930 Requires: krb5-devel %endif @@ -239,6 +240,7 @@ documentation. #%patch83 %patch86 #%patch89 +%patch90 %patch99 -p1 %patch100 -p1 @@ -299,6 +301,8 @@ rm -rf $RPM_BUILD_ROOT %{_datadir}/gtk-doc/html/* %changelog +* Fri Aug 17 2007 - jberkman@novell.com +- add auth support for smartcards (bug #273869) * Mon Aug 06 2007 - maw@suse.de - Split out a -lang subpackage - Don't package INSTALL.