gboolean goa_utils_delete_credentials_sync (GoaProvider *provider, GoaAccount *object, GCancellable *cancellable, GError **error) { gboolean ret; gchar *password_key; const gchar *id; GError *sec_error = NULL; g_return_val_if_fail (GOA_IS_PROVIDER (provider), FALSE); g_return_val_if_fail (GOA_IS_ACCOUNT (object), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); ret = FALSE; password_key = NULL; id = goa_account_get_id (object); password_key = g_strdup_printf ("%s:gen%d:%s", goa_provider_get_provider_type (GOA_PROVIDER (provider)), goa_provider_get_credentials_generation (GOA_PROVIDER (provider)), id); secret_password_clear_sync (&secret_password_schema, cancellable, &sec_error, "goa-identity", password_key, NULL); if (sec_error != NULL) { g_warning ("secret_password_clear_sync() failed: %s", sec_error->message); g_set_error_literal (error, GOA_ERROR, GOA_ERROR_FAILED, /* TODO: more specific */ _("Failed to delete credentials from the keyring")); g_error_free (sec_error); goto out; } g_debug ("Cleared keyring credentials for id: %s", id); ret = TRUE; out: g_free (password_key); return ret; }
static void get_all_providers_cb (GObject *source, GAsyncResult *res, gpointer user_data) { AddAccountData *data = user_data; GoaProvider *provider; GKeyFile *key_file; GError *error; GList *providers; GList *l; gchar *path; gchar *id; gchar *group; gchar *key_file_data; gsize length; gchar *object_path; GVariantIter iter; const gchar *key; const gchar *value; /* TODO: could check for @type */ provider = NULL; key_file = NULL; providers = NULL; path = NULL; id = NULL; group = NULL; key_file_data = NULL; object_path = NULL; if (!goa_provider_get_all_finish (&providers, res, NULL)) goto out; for (l = providers; l != NULL; l = l->next) { GoaProvider *p; const gchar *type; p = GOA_PROVIDER (l->data); type = goa_provider_get_provider_type (p); if (g_strcmp0 (type, data->provider_type) == 0) { provider = p; break; } } if (provider == NULL) { error= NULL; g_set_error (&error, GOA_ERROR, GOA_ERROR_FAILED, /* TODO: more specific */ _("Failed to find a provider for: %s"), data->provider_type); g_dbus_method_invocation_return_gerror (data->invocation, error); goto out; } key_file = g_key_file_new (); path = g_strdup_printf ("%s/goa-1.0/accounts.conf", g_get_user_config_dir ()); error = NULL; if (!g_file_get_contents (path, &key_file_data, &length, &error)) { if (error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT) { g_error_free (error); } else { g_prefix_error (&error, "Error loading file %s: ", path); g_dbus_method_invocation_return_gerror (data->invocation, error); goto out; } } else { if (length > 0) { error = NULL; if (!g_key_file_load_from_data (key_file, key_file_data, length, G_KEY_FILE_KEEP_COMMENTS, &error)) { g_prefix_error (&error, "Error parsing key-value-file %s: ", path); g_dbus_method_invocation_return_gerror (data->invocation, error); goto out; } } } id = generate_new_id (data->daemon); group = g_strdup_printf ("Account %s", id); g_key_file_set_string (key_file, group, "Provider", data->provider_type); g_key_file_set_string (key_file, group, "Identity", data->identity); g_key_file_set_string (key_file, group, "PresentationIdentity", data->presentation_identity); g_variant_iter_init (&iter, data->details); while (g_variant_iter_next (&iter, "{&s&s}", &key, &value)) { /* We treat IsTemporary special. If it's true we add in * the current session guid, so it can be ignored after * the session is over. */ if (g_strcmp0 (key, "IsTemporary") == 0) { if (g_strcmp0 (value, "true") == 0) { const char *guid; guid = g_dbus_connection_get_guid (data->daemon->connection); g_key_file_set_string (key_file, group, "SessionId", guid); } } g_key_file_set_string (key_file, group, key, value); } g_free (key_file_data); error = NULL; key_file_data = g_key_file_to_data (key_file, &length, &error); if (key_file_data == NULL) { g_prefix_error (&error, "Error generating key-value-file: "); g_dbus_method_invocation_return_gerror (data->invocation, error); goto out; } error = NULL; if (!g_file_set_contents (path, key_file_data, length, &error)) { g_prefix_error (&error, "Error writing key-value-file %s: ", path); g_dbus_method_invocation_return_gerror (data->invocation, error); goto out; } /* We don't want to fail AddAccount if we could not store the * credentials in the keyring. */ goa_utils_store_credentials_for_id_sync (provider, id, data->credentials, NULL, /* GCancellable */ NULL); goa_daemon_reload_configuration (data->daemon); object_path = g_strdup_printf ("/org/gnome/OnlineAccounts/Accounts/%s", id); goa_manager_complete_add_account (data->manager, data->invocation, object_path); out: g_free (object_path); if (providers != NULL) g_list_free_full (providers, g_object_unref); g_free (key_file_data); g_free (group); g_free (id); g_free (path); if (key_file != NULL) g_key_file_free (key_file); g_object_unref (data->daemon); g_object_unref (data->manager); g_object_unref (data->invocation); g_free (data->provider_type); g_free (data->identity); g_free (data->presentation_identity); g_variant_unref (data->credentials); g_variant_unref (data->details); g_slice_free (AddAccountData, data); }
gboolean goa_utils_store_credentials_for_id_sync (GoaProvider *provider, const gchar *id, GVariant *credentials, GCancellable *cancellable, GError **error) { gboolean ret; gchar *credentials_str; gchar *password_description; gchar *password_key; GError *sec_error = NULL; g_return_val_if_fail (GOA_IS_PROVIDER (provider), FALSE); g_return_val_if_fail (id != NULL && id[0] != '\0', FALSE); g_return_val_if_fail (credentials != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); ret = FALSE; credentials_str = g_variant_print (credentials, TRUE); g_variant_ref_sink (credentials); g_variant_unref (credentials); password_key = g_strdup_printf ("%s:gen%d:%s", goa_provider_get_provider_type (GOA_PROVIDER (provider)), goa_provider_get_credentials_generation (GOA_PROVIDER (provider)), id); /* Translators: The %s is the type of the provider, e.g. 'google' or 'yahoo' */ password_description = g_strdup_printf (_("GOA %s credentials for identity %s"), goa_provider_get_provider_type (GOA_PROVIDER (provider)), id); if (!secret_password_store_sync (&secret_password_schema, SECRET_COLLECTION_DEFAULT, /* default keyring */ password_description, credentials_str, cancellable, &sec_error, "goa-identity", password_key, NULL)) { g_warning ("secret_password_store_sync() failed: %s", sec_error->message); g_set_error_literal (error, GOA_ERROR, GOA_ERROR_FAILED, /* TODO: more specific */ _("Failed to store credentials in the keyring")); g_error_free (sec_error); goto out; } g_debug ("Stored keyring credentials for identity: %s", id); ret = TRUE; out: g_free (credentials_str); g_free (password_key); g_free (password_description); return ret; }
GVariant * goa_utils_lookup_credentials_sync (GoaProvider *provider, GoaObject *object, GCancellable *cancellable, GError **error) { gchar *password_key; GVariant *ret; gchar *password; const gchar *id; GError *sec_error = NULL; g_return_val_if_fail (GOA_IS_PROVIDER (provider), NULL); g_return_val_if_fail (GOA_IS_OBJECT (object) && goa_object_peek_account (object) != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); ret = NULL; password_key = NULL; password = NULL; id = goa_account_get_id (goa_object_peek_account (object)); password_key = g_strdup_printf ("%s:gen%d:%s", goa_provider_get_provider_type (GOA_PROVIDER (provider)), goa_provider_get_credentials_generation (GOA_PROVIDER (provider)), id); password = secret_password_lookup_sync (&secret_password_schema, cancellable, &sec_error, "goa-identity", password_key, NULL); if (sec_error != NULL) { g_warning ("secret_password_lookup_sync() failed: %s", sec_error->message); g_set_error_literal (error, GOA_ERROR, GOA_ERROR_FAILED, /* TODO: more specific */ _("Failed to retrieve credentials from the keyring")); g_error_free (sec_error); goto out; } else if (password == NULL) { g_warning ("secret_password_lookup_sync() returned NULL"); g_set_error_literal (error, GOA_ERROR, GOA_ERROR_FAILED, /* TODO: more specific */ _("No credentials found in the keyring")); goto out; } g_debug ("Retrieved keyring credentials for id: %s", id); ret = g_variant_parse (NULL, /* GVariantType */ password, NULL, /* limit */ NULL, /* endptr */ error); if (ret == NULL) { g_prefix_error (error, _("Error parsing result obtained from the keyring: ")); goto out; } if (g_variant_is_floating (ret)) g_variant_ref_sink (ret); out: g_free (password); g_free (password_key); return ret; }
static GoaObject * add_account (GoaProvider *provider, GoaClient *client, GtkDialog *dialog, GtkBox *vbox, GError **error) { AddAccountData data; GVariantBuilder credentials; GVariantBuilder details; GoaEwsClient *ews_client; GoaObject *ret; gboolean accept_ssl_errors; const gchar *email_address; const gchar *server; const gchar *password; const gchar *username; const gchar *provider_type; gint response; ews_client = NULL; accept_ssl_errors = FALSE; ret = NULL; memset (&data, 0, sizeof (AddAccountData)); data.loop = g_main_loop_new (NULL, FALSE); data.dialog = dialog; data.error = NULL; create_account_details_ui (provider, dialog, vbox, TRUE, &data); gtk_widget_show_all (GTK_WIDGET (vbox)); ews_client = goa_ews_client_new (); ews_again: response = gtk_dialog_run (dialog); if (response != GTK_RESPONSE_OK) { g_set_error (&data.error, GOA_ERROR, GOA_ERROR_DIALOG_DISMISSED, _("Dialog was dismissed")); goto out; } email_address = gtk_entry_get_text (GTK_ENTRY (data.email_address)); password = gtk_entry_get_text (GTK_ENTRY (data.password)); username = gtk_entry_get_text (GTK_ENTRY (data.username)); server = gtk_entry_get_text (GTK_ENTRY (data.server)); /* See if there's already an account of this type with the * given identity */ provider_type = goa_provider_get_provider_type (provider); if (!goa_utils_check_duplicate (client, username, provider_type, (GoaPeekInterfaceFunc) goa_object_peek_password_based, &data.error)) goto out; goa_ews_client_autodiscover (ews_client, email_address, password, username, server, accept_ssl_errors, NULL, autodiscover_cb, &data); goa_spinner_button_start (GOA_SPINNER_BUTTON (data.spinner_button)); g_main_loop_run (data.loop); if (data.error != NULL) { gchar *markup; if (data.error->code == GOA_ERROR_SSL) { goa_spinner_button_set_label (GOA_SPINNER_BUTTON (data.spinner_button), _("_Ignore")); accept_ssl_errors = TRUE; } else { goa_spinner_button_set_label (GOA_SPINNER_BUTTON (data.spinner_button), _("_Try Again")); accept_ssl_errors = FALSE; } markup = g_strdup_printf ("<b>%s:</b> %s", _("Error connecting to Microsoft Exchange server"), data.error->message); g_clear_error (&data.error); gtk_label_set_markup (GTK_LABEL (data.cluebar_label), markup); g_free (markup); gtk_expander_set_expanded (GTK_EXPANDER (data.expander), TRUE); gtk_widget_set_no_show_all (data.cluebar, FALSE); gtk_widget_show_all (data.cluebar); goto ews_again; } gtk_widget_hide (GTK_WIDGET (dialog)); g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&credentials, "{sv}", "password", g_variant_new_string (password)); g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}")); g_variant_builder_add (&details, "{ss}", "MailEnabled", "true"); g_variant_builder_add (&details, "{ss}", "CalendarEnabled", "true"); g_variant_builder_add (&details, "{ss}", "ContactsEnabled", "true"); g_variant_builder_add (&details, "{ss}", "Host", server); g_variant_builder_add (&details, "{ss}", "AcceptSslErrors", (accept_ssl_errors) ? "true" : "false"); /* OK, everything is dandy, add the account */ /* we want the GoaClient to update before this method returns (so it * can create a proxy for the new object) so run the mainloop while * waiting for this to complete */ goa_manager_call_add_account (goa_client_get_manager (client), goa_provider_get_provider_type (provider), username, email_address, g_variant_builder_end (&credentials), g_variant_builder_end (&details), NULL, /* GCancellable* */ (GAsyncReadyCallback) add_account_cb, &data); g_main_loop_run (data.loop); if (data.error != NULL) goto out; ret = GOA_OBJECT (g_dbus_object_manager_get_object (goa_client_get_object_manager (client), data.account_object_path)); out: /* We might have an object even when data.error is set. * eg., if we failed to store the credentials in the keyring. */ if (data.error != NULL) g_propagate_error (error, data.error); else g_assert (ret != NULL); g_free (data.account_object_path); if (data.loop != NULL) g_main_loop_unref (data.loop); if (ews_client != NULL) g_object_unref (ews_client); return ret; }