2 * @file gnomekeyring.c Gnome keyring password storage
8 * Purple is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program ; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
30 #include "glibcompat.h"
35 #include <gnome-keyring.h>
36 #include <gnome-keyring-memory.h>
38 #warning Gnome-Keyring API is deprecated, please use libSecret keyring instead.
40 #define GNOMEKEYRING_NAME N_("GNOME Keyring")
41 #define GNOMEKEYRING_DESCRIPTION N_("This plugin will store passwords in " \
43 #define GNOMEKEYRING_ID "keyring-gnomekeyring"
44 #define GNOMEKEYRING_AUTHORS \
45 { "Tomek Wasilczyk <twasilczyk@pidgin.im>", NULL }
47 #define GNOMEKEYRING_DOMAIN (g_quark_from_static_string(GNOMEKEYRING_ID))
49 static PurpleKeyring
*keyring_handler
= NULL
;
50 static GList
*request_queue
= NULL
;
51 static gpointer current_request
= NULL
;
57 GNOMEKEYRING_REQUEST_READ
,
58 GNOMEKEYRING_REQUEST_SAVE
60 PurpleAccount
*account
;
64 PurpleKeyringReadCallback read
;
65 PurpleKeyringSaveCallback save
;
69 } gnomekeyring_request
;
71 static void gnomekeyring_cancel_queue(void);
72 static void gnomekeyring_process_queue(void);
74 static void gnomekeyring_request_free(gnomekeyring_request
*req
)
76 if (req
->password
!= NULL
) {
77 memset(req
->password
, 0, strlen(req
->password
));
78 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
79 gnome_keyring_memory_free(req
->password
);
80 G_GNUC_END_IGNORE_DEPRECATIONS
86 gnomekeyring_enqueue(gnomekeyring_request
*req
)
88 request_queue
= g_list_append(request_queue
, req
);
89 gnomekeyring_process_queue();
93 gnomekeyring_read_cb(GnomeKeyringResult result
, const char *password
,
96 gnomekeyring_request
*req
= _req
;
97 PurpleAccount
*account
;
100 g_return_if_fail(req
!= NULL
);
102 current_request
= NULL
;
103 account
= req
->account
;
105 if (result
== GNOME_KEYRING_RESULT_OK
) {
107 } else if (result
== GNOME_KEYRING_RESULT_NO_MATCH
) {
108 error
= g_error_new(PURPLE_KEYRING_ERROR
,
109 PURPLE_KEYRING_ERROR_NOPASSWORD
,
110 _("No password found for account."));
111 } else if (result
== GNOME_KEYRING_RESULT_DENIED
||
112 result
== GNOME_KEYRING_RESULT_CANCELLED
)
114 error
= g_error_new(PURPLE_KEYRING_ERROR
,
115 PURPLE_KEYRING_ERROR_ACCESSDENIED
,
116 _("Access denied."));
117 gnomekeyring_cancel_queue();
118 } else if (result
== GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON
||
119 result
== GNOME_KEYRING_RESULT_IO_ERROR
)
121 error
= g_error_new(PURPLE_KEYRING_ERROR
,
122 PURPLE_KEYRING_ERROR_BACKENDFAIL
,
123 _("Communication with GNOME Keyring failed."));
125 error
= g_error_new(PURPLE_KEYRING_ERROR
,
126 PURPLE_KEYRING_ERROR_BACKENDFAIL
,
127 _("Unknown error (code: %d)."), result
);
130 if (error
== NULL
&& password
== NULL
) {
131 error
= g_error_new(PURPLE_KEYRING_ERROR
,
132 PURPLE_KEYRING_ERROR_BACKENDFAIL
,
133 _("Unknown error (password empty)."));
137 purple_debug_misc("keyring-gnome",
138 "Got password for account %s (%s).\n",
139 purple_account_get_username(account
),
140 purple_account_get_protocol_id(account
));
141 } else if (result
== GNOME_KEYRING_RESULT_NO_MATCH
) {
142 if (purple_debug_is_verbose()) {
143 purple_debug_info("keyring-gnome",
144 "Password for account %s (%s) isn't stored.\n",
145 purple_account_get_username(account
),
146 purple_account_get_protocol_id(account
));
150 purple_debug_warning("keyring-gnome", "Failed to read "
151 "password for account %s (%s), code: %d.\n",
152 purple_account_get_username(account
),
153 purple_account_get_protocol_id(account
),
157 if (req
->cb
.read
!= NULL
)
158 req
->cb
.read(account
, password
, error
, req
->cb_data
);
164 gnomekeyring_process_queue();
168 gnomekeyring_save_cb(GnomeKeyringResult result
, gpointer _req
)
170 gnomekeyring_request
*req
= _req
;
171 PurpleAccount
*account
;
172 GError
*error
= NULL
;
173 gboolean already_removed
= FALSE
;
175 g_return_if_fail(req
!= NULL
);
177 current_request
= NULL
;
178 account
= req
->account
;
180 if (result
== GNOME_KEYRING_RESULT_OK
) {
182 } else if (result
== GNOME_KEYRING_RESULT_NO_MATCH
&&
183 req
->password
== NULL
)
186 already_removed
= TRUE
;
187 } else if (result
== GNOME_KEYRING_RESULT_DENIED
||
188 result
== GNOME_KEYRING_RESULT_CANCELLED
)
190 error
= g_error_new(PURPLE_KEYRING_ERROR
,
191 PURPLE_KEYRING_ERROR_ACCESSDENIED
,
192 _("Access denied."));
193 gnomekeyring_cancel_queue();
194 } else if (result
== GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON
||
195 result
== GNOME_KEYRING_RESULT_IO_ERROR
)
197 error
= g_error_new(PURPLE_KEYRING_ERROR
,
198 PURPLE_KEYRING_ERROR_BACKENDFAIL
,
199 _("Communication with GNOME Keyring failed."));
201 error
= g_error_new(PURPLE_KEYRING_ERROR
,
202 PURPLE_KEYRING_ERROR_BACKENDFAIL
,
203 _("Unknown error (code: %d)."), result
);
206 if (already_removed
) {
208 } else if (error
== NULL
) {
209 purple_debug_misc("keyring-gnome",
210 "Password %s for account %s (%s).\n",
211 req
->password
? "saved" : "removed",
212 purple_account_get_username(account
),
213 purple_account_get_protocol_id(account
));
215 purple_debug_warning("keyring-gnome", "Failed updating "
216 "password for account %s (%s), code: %d.\n",
217 purple_account_get_username(account
),
218 purple_account_get_protocol_id(account
),
222 if (req
->cb
.save
!= NULL
)
223 req
->cb
.save(account
, error
, req
->cb_data
);
229 gnomekeyring_process_queue();
233 gnomekeyring_request_cancel(gpointer _req
)
235 gnomekeyring_request
*req
= _req
;
236 PurpleAccount
*account
;
239 g_return_if_fail(req
!= NULL
);
242 gnomekeyring_request_free(req
);
246 purple_debug_warning("keyring-gnome",
247 "operation cancelled (%d %s:%s)\n", req
->type
,
248 purple_account_get_protocol_id(req
->account
),
249 purple_account_get_username(req
->account
));
251 account
= req
->account
;
252 error
= g_error_new(PURPLE_KEYRING_ERROR
,
253 PURPLE_KEYRING_ERROR_CANCELLED
,
254 _("Operation cancelled."));
255 if (req
->type
== GNOMEKEYRING_REQUEST_READ
&& req
->cb
.read
)
256 req
->cb
.read(account
, NULL
, error
, req
->cb_data
);
257 if (req
->type
== GNOMEKEYRING_REQUEST_SAVE
&& req
->cb
.save
)
258 req
->cb
.save(account
, error
, req
->cb_data
);
261 gnomekeyring_request_free(req
);
262 gnomekeyring_process_queue();
266 gnomekeyring_cancel_queue(void)
268 GList
*cancel_list
= request_queue
;
270 if (request_queue
== NULL
)
273 purple_debug_info("gnome-keyring", "cancelling all pending requests\n");
274 request_queue
= NULL
;
276 g_list_free_full(cancel_list
, gnomekeyring_request_cancel
);
280 gnomekeyring_process_queue(void)
282 gnomekeyring_request
*req
;
283 PurpleAccount
*account
;
286 if (request_queue
== NULL
)
289 if (current_request
) {
290 if (purple_debug_is_verbose())
291 purple_debug_misc("keyring-gnome", "busy...\n");
295 first
= g_list_first(request_queue
);
297 request_queue
= g_list_delete_link(request_queue
, first
);
298 account
= req
->account
;
300 if (purple_debug_is_verbose()) {
301 purple_debug_misc("keyring-gnome",
302 "%s password for account %s (%s)\n",
303 req
->type
== GNOMEKEYRING_REQUEST_READ
? "reading" :
304 (req
->password
== NULL
? "removing" : "updating"),
305 purple_account_get_username(account
),
306 purple_account_get_protocol_id(account
));
309 if (req
->type
== GNOMEKEYRING_REQUEST_READ
) {
310 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
311 current_request
= gnome_keyring_find_password(
312 GNOME_KEYRING_NETWORK_PASSWORD
, gnomekeyring_read_cb
,
313 req
, gnomekeyring_request_cancel
,
314 "user", purple_account_get_username(account
),
315 "protocol", purple_account_get_protocol_id(account
),
317 G_GNUC_END_IGNORE_DEPRECATIONS
318 } else if (req
->type
== GNOMEKEYRING_REQUEST_SAVE
&&
319 req
->password
!= NULL
)
321 gchar
*display_name
= g_strdup_printf(
322 _("Pidgin IM password for account %s"),
323 purple_account_get_username(account
));
324 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
325 current_request
= gnome_keyring_store_password(
326 GNOME_KEYRING_NETWORK_PASSWORD
, GNOME_KEYRING_DEFAULT
,
327 display_name
, req
->password
, gnomekeyring_save_cb
, req
,
328 gnomekeyring_request_cancel
,
329 "user", purple_account_get_username(account
),
330 "protocol", purple_account_get_protocol_id(account
),
332 G_GNUC_END_IGNORE_DEPRECATIONS
333 g_free(display_name
);
334 } else if (req
->type
== GNOMEKEYRING_REQUEST_SAVE
&&
335 req
->password
== NULL
)
337 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
338 current_request
= gnome_keyring_delete_password(
339 GNOME_KEYRING_NETWORK_PASSWORD
, gnomekeyring_save_cb
,
340 req
, gnomekeyring_request_cancel
,
341 "user", purple_account_get_username(account
),
342 "protocol", purple_account_get_protocol_id(account
),
344 G_GNUC_END_IGNORE_DEPRECATIONS
346 g_return_if_reached();
351 gnomekeyring_read(PurpleAccount
*account
, PurpleKeyringReadCallback cb
,
354 gnomekeyring_request
*req
;
356 g_return_if_fail(account
!= NULL
);
358 req
= g_new0(gnomekeyring_request
, 1);
359 req
->type
= GNOMEKEYRING_REQUEST_READ
;
360 req
->account
= account
;
364 gnomekeyring_enqueue(req
);
368 gnomekeyring_save(PurpleAccount
*account
, const gchar
*password
,
369 PurpleKeyringSaveCallback cb
, gpointer data
)
371 gnomekeyring_request
*req
;
373 g_return_if_fail(account
!= NULL
);
375 req
= g_new0(gnomekeyring_request
, 1);
376 req
->type
= GNOMEKEYRING_REQUEST_SAVE
;
377 req
->account
= account
;
378 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
379 req
->password
= gnome_keyring_memory_strdup(password
);
380 G_GNUC_END_IGNORE_DEPRECATIONS
384 gnomekeyring_enqueue(req
);
388 gnomekeyring_cancel(void)
390 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
391 gnomekeyring_cancel_queue();
392 G_GNUC_END_IGNORE_DEPRECATIONS
393 if (current_request
) {
394 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
395 gnome_keyring_cancel_request(current_request
);
396 G_GNUC_END_IGNORE_DEPRECATIONS
397 while (g_main_iteration(FALSE
));
402 gnomekeyring_close(void)
404 gnomekeyring_cancel();
407 static PurplePluginInfo
*
408 plugin_query(GError
**error
)
410 const gchar
* const authors
[] = GNOMEKEYRING_AUTHORS
;
412 return purple_plugin_info_new(
413 "id", GNOMEKEYRING_ID
,
414 "name", GNOMEKEYRING_NAME
,
415 "version", DISPLAY_VERSION
,
416 "category", N_("Keyring"),
417 "summary", "GNOME Keyring Plugin",
418 "description", GNOMEKEYRING_DESCRIPTION
,
420 "website", PURPLE_WEBSITE
,
421 "abi-version", PURPLE_ABI_VERSION
,
422 "flags", PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
,
428 plugin_load(PurplePlugin
*plugin
, GError
**error
)
432 /* libgnome-keyring may crash, if was unloaded before glib main loop
435 gkr_module
= g_module_open("libgnome-keyring", 0);
436 if (gkr_module
== NULL
) {
437 gkr_module
= g_module_open("libgnome-keyring.so.0", 0);
438 if (gkr_module
== NULL
) {
439 gkr_module
= g_module_open("libgnome-keyring.so.1", 0);
442 if (gkr_module
== NULL
) {
443 purple_debug_info("keyring-gnome", "GNOME Keyring module not "
447 g_module_make_resident(gkr_module
);
449 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
450 if (!gnome_keyring_is_available()) {
451 G_GNUC_END_IGNORE_DEPRECATIONS
452 g_set_error(error
, GNOMEKEYRING_DOMAIN
, 0, "GNOME Keyring service is "
454 purple_debug_info("keyring-gnome", "GNOME Keyring service is "
459 keyring_handler
= purple_keyring_new();
461 purple_keyring_set_name(keyring_handler
, _(GNOMEKEYRING_NAME
));
462 purple_keyring_set_id(keyring_handler
, GNOMEKEYRING_ID
);
463 purple_keyring_set_read_password(keyring_handler
, gnomekeyring_read
);
464 purple_keyring_set_save_password(keyring_handler
, gnomekeyring_save
);
465 purple_keyring_set_cancel_requests(keyring_handler
,
466 gnomekeyring_cancel
);
467 purple_keyring_set_close_keyring(keyring_handler
, gnomekeyring_close
);
469 purple_keyring_register(keyring_handler
);
475 plugin_unload(PurplePlugin
*plugin
, GError
**error
)
477 if (purple_keyring_get_inuse() == keyring_handler
) {
478 g_set_error(error
, GNOMEKEYRING_DOMAIN
, 0, "The keyring is currently "
480 purple_debug_warning("keyring-gnome",
481 "keyring in use, cannot unload\n");
485 gnomekeyring_close();
487 purple_keyring_unregister(keyring_handler
);
488 purple_keyring_free(keyring_handler
);
489 keyring_handler
= NULL
;
494 PURPLE_PLUGIN_INIT(gnome_keyring
, plugin_query
, plugin_load
, plugin_unload
);