Merge lp:~mitya57/ubuntu/raring/gnome-keyring/dbus-fixes into lp:ubuntu/raring/gnome-keyring

Proposed by Dmitry Shachnev
Status: Merged
Merge reported by: Sebastien Bacher
Merged at revision: not available
Proposed branch: lp:~mitya57/ubuntu/raring/gnome-keyring/dbus-fixes
Merge into: lp:ubuntu/raring/gnome-keyring
Diff against target: 4024 lines (+3877/-24)
13 files modified
.pc/00git_fix_introspection.patch/daemon/dbus/gkd-secret-introspect.c (+285/-0)
.pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.c (+1710/-0)
.pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.h (+112/-0)
.pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-service.c (+1598/-0)
.pc/applied-patches (+2/-0)
daemon/dbus/gkd-secret-introspect.c (+2/-3)
daemon/dbus/gkd-secret-objects.c (+29/-19)
daemon/dbus/gkd-secret-objects.h (+2/-1)
daemon/dbus/gkd-secret-service.c (+1/-1)
debian/changelog (+9/-0)
debian/patches/00git_fix_introspection.patch (+26/-0)
debian/patches/00git_fix_searchitems_method.patch (+99/-0)
debian/patches/series (+2/-0)
To merge this branch: bzr merge lp:~mitya57/ubuntu/raring/gnome-keyring/dbus-fixes
Reviewer Review Type Date Requested Status
Ubuntu branches Pending
Review via email: mp+152580@code.launchpad.net

Description of the change

Added two upstream patches to fix D-Bus related issues.

* debian/patches/00git_fix_searchitems_method.patch:
  Upstream patch to fix return value of Collection.SearchItems().
* debian/patches/00git_fix_introspection.patch:
  Upstream patch to fix introspection of some D-Bus methods.

To post a comment you must log in.
Revision history for this message
Dmitry Shachnev (mitya57) wrote :

FWIW, I've also reviewed all the implementations I know to make sure this doesn't cause any regressions:

- libsecret: expect the *right* behavior (confirmed by Stef Walter);
- python-secretstorage: handles both cases correctly;
- ubuntu-sso-client, python-keyring: do not use that function at all.

161. By Dmitry Shachnev

Rename 05_fix_introspection.patch to 00git_fix_introspection.patch
now that it has been applied upstream

162. By Dmitry Shachnev

Update .pc directory so that the branch is buildable

Revision history for this message
Sebastien Bacher (seb128) wrote :

Thanks, uploaded to raring. Upstream asked if you want some fixes backported to the gnome-3-6 serie, it could be good to have those officially in there

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc/00git_fix_introspection.patch'
2=== added directory '.pc/00git_fix_introspection.patch/daemon'
3=== added directory '.pc/00git_fix_introspection.patch/daemon/dbus'
4=== added file '.pc/00git_fix_introspection.patch/daemon/dbus/gkd-secret-introspect.c'
5--- .pc/00git_fix_introspection.patch/daemon/dbus/gkd-secret-introspect.c 1970-01-01 00:00:00 +0000
6+++ .pc/00git_fix_introspection.patch/daemon/dbus/gkd-secret-introspect.c 2013-03-14 13:26:21 +0000
7@@ -0,0 +1,285 @@
8+/*
9+ * gnome-keyring
10+ *
11+ * Copyright (C) 2011 Collabora Ltd.
12+ *
13+ * This program is free software; you can redistribute it and/or modify
14+ * it under the terms of the GNU Lesser General Public License as
15+ * published by the Free Software Foundation; either version 2.1 of
16+ * the License, or (at your option) any later version.
17+ *
18+ * This program is distributed in the hope that it will be useful, but
19+ * WITHOUT ANY WARRANTY; without even the implied warranty of
20+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21+ * Lesser General Public License for more details.
22+ *
23+ * You should have received a copy of the GNU Lesser General Public
24+ * License along with this program; if not, write to the Free Software
25+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
26+ * 02111-1307, USA.
27+ *
28+ * Author: Stef Walter <stefw@collabora.co.uk>
29+ */
30+
31+#include "config.h"
32+
33+#include "gkd-secret-introspect.h"
34+
35+const gchar *gkd_secret_introspect_root =
36+ "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
37+ " 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
38+ "<node>\n"
39+ " <node name='org/freedesktop/secrets'/>\n"
40+ "</node>\n";
41+
42+const gchar *gkd_secret_introspect_collection =
43+ "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
44+ " 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
45+ "<node>\n"
46+ "\n"
47+ " <interface name='org.freedesktop.DBus.Introspectable'>\n"
48+ " <method name='Introspect'>\n"
49+ " <arg name='data' direction='out' type='s'/>\n"
50+ " </method>\n"
51+ " </interface>\n"
52+ "\n"
53+ " <interface name='org.freedesktop.DBus.Properties'>\n"
54+ " <method name='Get'>\n"
55+ " <arg name='interface' direction='in' type='s'/>\n"
56+ " <arg name='propname' direction='in' type='s'/>\n"
57+ " <arg name='value' direction='out' type='v'/>\n"
58+ " </method>\n"
59+ " <method name='Set'>\n"
60+ " <arg name='interface' direction='in' type='s'/>\n"
61+ " <arg name='propname' direction='in' type='s'/>\n"
62+ " <arg name='value' direction='in' type='v'/>\n"
63+ " </method>\n"
64+ " <method name='GetAll'>\n"
65+ " <arg name='interface' direction='in' type='s'/>\n"
66+ " <arg name='props' direction='out' type='a{sv}'/>\n"
67+ " </method>\n"
68+ " </interface>\n"
69+ "\n"
70+ " <interface name='org.freedesktop.Secret.Collection'>\n"
71+ " <property name='Items' type='ao' access='read'/>\n"
72+ " <property name='Label' type='s' access='readwrite'/>\n"
73+ " <property name='Locked' type='s' access='read'/>\n"
74+ " <property name='Created' type='t' access='read'/>\n"
75+ " <property name='Modified' type='t' access='read'/>\n"
76+ " <method name='Delete'>\n"
77+ " <arg name='prompt' type='o' direction='out'/>\n"
78+ " </method>\n"
79+ " <method name='SearchItems'>\n"
80+ " <arg name='attributes' type='a{ss}' direction='in'/>\n"
81+ " <arg name='unlocked' type='ao' direction='out'/>\n"
82+ " <arg name='locked' type='ao' direction='out'/>\n"
83+ " </method>\n"
84+ " <method name='CreateItem'>\n"
85+ " <arg name='props' type='a{sv}' direction='in'/>\n"
86+ " <arg name='secret' type='(oayays)' direction='in'/>\n"
87+ " <arg name='replace' type='b' direction='in'/>\n"
88+ " <arg name='item' type='o' direction='out'/>\n"
89+ " <arg name='prompt' type='o' direction='out'/>\n"
90+ " </method>\n"
91+ " <signal name='ItemCreated'>\n"
92+ " <arg name='item' type='o'/>\n"
93+ " </signal>\n"
94+ " <signal name='ItemDeleted'>\n"
95+ " <arg name='item' type='o'/>\n"
96+ " </signal>\n"
97+ " <signal name='ItemChanged'>\n"
98+ " <arg name='item' type='o'/>\n"
99+ " </signal>\n"
100+ " </interface>\n"
101+ "\n"
102+ "<!--@children@-->"
103+ "</node>\n";
104+
105+const gchar *gkd_secret_introspect_item =
106+ "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
107+ " 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
108+ "<node>\n"
109+ "\n"
110+ " <interface name='org.freedesktop.DBus.Introspectable'>\n"
111+ " <method name='Introspect'>\n"
112+ " <arg name='data' direction='out' type='s'/>\n"
113+ " </method>\n"
114+ " </interface>\n"
115+ "\n"
116+ " <interface name='org.freedesktop.DBus.Properties'>\n"
117+ " <method name='Get'>\n"
118+ " <arg name='interface' direction='in' type='s'/>\n"
119+ " <arg name='propname' direction='in' type='s'/>\n"
120+ " <arg name='value' direction='out' type='v'/>\n"
121+ " </method>\n"
122+ " <method name='Set'>\n"
123+ " <arg name='interface' direction='in' type='s'/>\n"
124+ " <arg name='propname' direction='in' type='s'/>\n"
125+ " <arg name='value' direction='in' type='v'/>\n"
126+ " </method>\n"
127+ " <method name='GetAll'>\n"
128+ " <arg name='interface' direction='in' type='s'/>\n"
129+ " <arg name='props' direction='out' type='a{sv}'/>\n"
130+ " </method>\n"
131+ " </interface>\n"
132+ "\n"
133+ " <interface name='org.freedesktop.Secret.Item'>\n"
134+ " <property name='Locked' type='b' access='read'/>\n"
135+ " <property name='Attributes' type='a{ss}' access='readwrite'/>\n"
136+ " <property name='Label' type='s' access='readwrite'/>\n"
137+ " <property name='Type' type='s' access='readwrite'/>\n"
138+ " <property name='Created' type='t' access='read'/>\n"
139+ " <property name='Modified' type='t' access='read'/>\n"
140+ " <method name='Delete'>\n"
141+ " <arg name='prompt' type='o' direction='out'/>\n"
142+ " </method>\n"
143+ " <method name='GetSecret'>\n"
144+ " <arg name='session' type='o' direction='in'/>\n"
145+ " <arg name='secret' type='(oayays)' direction='out'/>\n"
146+ " </method>\n"
147+ " <method name='SetSecret'>\n"
148+ " <arg name='secret' type='(oayays)' direction='in'/>\n"
149+ " </method>\n"
150+ " </interface>\n"
151+ "\n"
152+ "</node>\n";
153+
154+const gchar *gkd_secret_introspect_prompt =
155+ "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
156+ " 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
157+ "<node>\n"
158+ "\n"
159+ " <interface name='org.freedesktop.DBus.Introspectable'>\n"
160+ " <method name='Introspect'>\n"
161+ " <arg name='data' direction='out' type='s'/>\n"
162+ " </method>\n"
163+ " </interface>\n"
164+ "\n"
165+ " <interface name='org.freedesktop.Secret.Prompt'>\n"
166+ " <method name='Prompt'>\n"
167+ " <arg name='window-id' type='s' direction='in'/>\n"
168+ " </method>\n"
169+ " <method name='Dismiss'>\n"
170+ " </method>\n"
171+ " <signal name='Completed'>\n"
172+ " <arg name='dismissed' type='b'/>\n"
173+ " <arg name='result' type='v'/>\n"
174+ " </signal>\n"
175+ " </interface>\n"
176+ "\n"
177+ "</node>\n";
178+
179+const gchar *gkd_secret_introspect_service =
180+ "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
181+ " 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
182+ "<node>\n"
183+ "\n"
184+ " <interface name='org.freedesktop.DBus.Introspectable'>\n"
185+ " <method name='Introspect'>\n"
186+ " <arg name='data' direction='out' type='s'/>\n"
187+ " </method>\n"
188+ " </interface>\n"
189+ "\n"
190+ " <interface name='org.freedesktop.DBus.Properties'>\n"
191+ " <method name='Get'>\n"
192+ " <arg name='interface' direction='in' type='s'/>\n"
193+ " <arg name='propname' direction='in' type='s'/>\n"
194+ " <arg name='value' direction='out' type='v'/>\n"
195+ " </method>\n"
196+ " <method name='Set'>\n"
197+ " <arg name='interface' direction='in' type='s'/>\n"
198+ " <arg name='propname' direction='in' type='s'/>\n"
199+ " <arg name='value' direction='in' type='v'/>\n"
200+ " </method>\n"
201+ " <method name='GetAll'>\n"
202+ " <arg name='interface' direction='in' type='s'/>\n"
203+ " <arg name='props' direction='out' type='a{sv}'/>\n"
204+ " </method>\n"
205+ " </interface>\n"
206+ "\n"
207+ " <interface name='org.freedesktop.Secret.Service'>\n"
208+ "\n"
209+ " <property name='Collections' type='ao' access='read'/>\n"
210+ "\n"
211+ " <method name='OpenSession'>\n"
212+ " <arg name='algorithm' type='s' direction='in'/>\n"
213+ " <arg name='input' type='v' direction='in'/>\n"
214+ " <arg name='output' type='v' direction='out'/>\n"
215+ " <arg name='result' type='o' direction='out'/>\n"
216+ " </method>\n"
217+ "\n"
218+ " <method name='CreateCollection'>\n"
219+ " <arg name='properties' type='a{sv}' direction='in'/>\n"
220+ " <arg name='alias' type='s' direction='in'/>\n"
221+ " <arg name='collection' type='o' direction='out'/>\n"
222+ " <arg name='prompt' type='o' direction='out'/>\n"
223+ " </method>\n"
224+ "\n"
225+ " <method name='SearchItems'>\n"
226+ " <arg name='attributes' type='a{ss}' direction='in'/>\n"
227+ " <arg name='unlocked' type='ao' direction='out'/>\n"
228+ " <arg name='locked' type='ao' direction='out'/>\n"
229+ " </method>\n"
230+ "\n"
231+ " <method name='Unlock'>\n"
232+ " <arg name='objects' type='ao' direction='in'/>\n"
233+ " <arg name='unlocked' type='ao' direction='out'/>\n"
234+ " <arg name='prompt' type='o' direction='out'/>\n"
235+ " </method>\n"
236+ "\n"
237+ " <method name='Lock'>\n"
238+ " <arg name='objects' type='ao' direction='in'/>\n"
239+ " <arg name='locked' type='ao' direction='out'/>\n"
240+ " <arg name='Prompt' type='o' direction='out'/>\n"
241+ " </method>\n"
242+ "\n"
243+ " <method name='GetSecrets'>\n"
244+ " <arg name='items' type='ao' direction='in'/>\n"
245+ " <arg name='session' type='o' direction='in'/>\n"
246+ " <arg name='secrets' type='a{o(oayays)}' direction='out'/>\n"
247+ " </method>\n"
248+ "\n"
249+ " <method name='ReadAlias'>\n"
250+ " <arg name='name' type='s' direction='in'/>\n"
251+ " <arg name='collection' type='o' direction='out'/>\n"
252+ " </method>\n"
253+ "\n"
254+ " <method name='SetAlias'>\n"
255+ " <arg name='name' type='s' direction='in'/>\n"
256+ " <arg name='collection' type='o' direction='in'/>\n"
257+ " </method>\n"
258+ "\n"
259+ " <signal name='CollectionCreated'>\n"
260+ " <arg name='collection' type='o'/>\n"
261+ " </signal>\n"
262+ "\n"
263+ " <signal name='CollectionDeleted'>\n"
264+ " <arg name='collection' type='o'/>\n"
265+ " </signal>\n"
266+ "\n"
267+ " <signal name='CollectionChanged'>\n"
268+ " <arg name='collection' type='o'/>\n"
269+ " </signal>\n"
270+ "\n"
271+ " </interface>\n"
272+ "\n"
273+ "<!--@children@-->"
274+ "</node>\n";
275+
276+const gchar *gkd_secret_introspect_session =
277+ "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
278+ " 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
279+ "<node>\n"
280+ "\n"
281+ " <interface name='org.freedesktop.DBus.Introspectable'>\n"
282+ " <method name='Introspect'>\n"
283+ " <arg name='data' direction='out' type='s'/>\n"
284+ " </method>\n"
285+ " </interface>\n"
286+ "\n"
287+ " <interface name='org.freedesktop.Secret.Session'>\n"
288+ " <method name='Close'>\n"
289+ " </method>\n"
290+ " </interface>\n"
291+ "\n"
292+ "</node>\n";
293
294=== added directory '.pc/00git_fix_searchitems_method.patch'
295=== added directory '.pc/00git_fix_searchitems_method.patch/daemon'
296=== added directory '.pc/00git_fix_searchitems_method.patch/daemon/dbus'
297=== added file '.pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.c'
298--- .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.c 1970-01-01 00:00:00 +0000
299+++ .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.c 2013-03-14 13:26:21 +0000
300@@ -0,0 +1,1710 @@
301+/*
302+ * gnome-keyring
303+ *
304+ * Copyright (C) 2008 Stefan Walter
305+ *
306+ * This program is free software; you can redistribute it and/or modify
307+ * it under the terms of the GNU Lesser General Public License as
308+ * published by the Free Software Foundation; either version 2.1 of
309+ * the License, or (at your option) any later version.
310+ *
311+ * This program is distributed in the hope that it will be useful, but
312+ * WITHOUT ANY WARRANTY; without even the implied warranty of
313+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
314+ * Lesser General Public License for more details.
315+ *
316+ * You should have received a copy of the GNU Lesser General Public
317+ * License along with this program; if not, write to the Free Software
318+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
319+ * 02111-1307, USA.
320+ */
321+
322+#include "config.h"
323+
324+#include "gkd-dbus-util.h"
325+
326+#include "gkd-secret-error.h"
327+#include "gkd-secret-introspect.h"
328+#include "gkd-secret-objects.h"
329+#include "gkd-secret-property.h"
330+#include "gkd-secret-secret.h"
331+#include "gkd-secret-service.h"
332+#include "gkd-secret-session.h"
333+#include "gkd-secret-types.h"
334+#include "gkd-secret-util.h"
335+
336+#include "egg/egg-error.h"
337+
338+#include "pkcs11/pkcs11i.h"
339+
340+#include <string.h>
341+
342+enum {
343+ PROP_0,
344+ PROP_PKCS11_SLOT,
345+ PROP_SERVICE
346+};
347+
348+struct _GkdSecretObjects {
349+ GObject parent;
350+ GkdSecretService *service;
351+ GckSlot *pkcs11_slot;
352+};
353+
354+static gchar * object_path_for_item (const gchar *base,
355+ GckObject *item);
356+
357+static gchar * object_path_for_collection (GckObject *collection);
358+
359+static gchar * collection_path_for_item (GckObject *item);
360+
361+G_DEFINE_TYPE (GkdSecretObjects, gkd_secret_objects, G_TYPE_OBJECT);
362+
363+/* -----------------------------------------------------------------------------
364+ * INTERNAL
365+ */
366+
367+static gboolean
368+parse_object_path (GkdSecretObjects *self, const gchar *path, gchar **collection, gchar **item)
369+{
370+ const gchar *replace;
371+
372+ g_assert (self);
373+ g_assert (path);
374+ g_assert (collection);
375+
376+ if (!gkd_secret_util_parse_path (path, collection, item))
377+ return FALSE;
378+
379+ if (g_str_has_prefix (path, SECRET_ALIAS_PREFIX)) {
380+ replace = gkd_secret_service_get_alias (self->service, *collection);
381+ if (!replace) {
382+ g_free (*collection);
383+ *collection = NULL;
384+ if (item) {
385+ g_free (*item);
386+ *item = NULL;
387+ }
388+ return FALSE;
389+ }
390+ g_free (*collection);
391+ *collection = g_strdup (replace);
392+ }
393+
394+ return TRUE;
395+}
396+
397+static DBusMessage*
398+object_property_get (GckObject *object, DBusMessage *message,
399+ const gchar *prop_name)
400+{
401+ DBusMessageIter iter;
402+ GError *error = NULL;
403+ DBusMessage *reply;
404+ GckAttribute attr;
405+ gpointer value;
406+ gsize length;
407+
408+ if (!gkd_secret_property_get_type (prop_name, &attr.type))
409+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
410+ "Object does not have the '%s' property", prop_name);
411+
412+ /* Retrieve the actual attribute */
413+ attr.value = value = gck_object_get_data (object, attr.type, NULL, &length, &error);
414+ if (error != NULL) {
415+ reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
416+ "Couldn't retrieve '%s' property: %s",
417+ prop_name, egg_error_message (error));
418+ g_clear_error (&error);
419+ return reply;
420+ }
421+
422+ /* Marshall the data back out */
423+ attr.length = length;
424+ reply = dbus_message_new_method_return (message);
425+ dbus_message_iter_init_append (reply, &iter);
426+ gkd_secret_property_append_variant (&iter, &attr);
427+ g_free (value);
428+ return reply;
429+}
430+
431+static DBusMessage*
432+object_property_set (GckObject *object,
433+ DBusMessage *message,
434+ DBusMessageIter *iter,
435+ const gchar *prop_name)
436+{
437+ GckBuilder builder = GCK_BUILDER_INIT;
438+ DBusMessage *reply;
439+ GError *error = NULL;
440+ gulong attr_type;
441+
442+ g_return_val_if_fail (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_VARIANT, NULL);
443+
444+ /* What type of property is it? */
445+ if (!gkd_secret_property_get_type (prop_name, &attr_type))
446+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
447+ "Object does not have the '%s' property", prop_name);
448+
449+ /* Retrieve the actual attribute value */
450+ if (!gkd_secret_property_parse_variant (iter, prop_name, &builder)) {
451+ gck_builder_clear (&builder);
452+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
453+ "The property type or value was invalid: %s", prop_name);
454+ }
455+
456+ gck_object_set (object, gck_builder_end (&builder), NULL, &error);
457+
458+ if (error != NULL) {
459+ if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
460+ reply = dbus_message_new_error (message, SECRET_ERROR_IS_LOCKED,
461+ "Cannot set property on a locked object");
462+ else
463+ reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
464+ "Couldn't set '%s' property: %s",
465+ prop_name, egg_error_message (error));
466+ g_clear_error (&error);
467+ return reply;
468+ }
469+
470+ return dbus_message_new_method_return (message);
471+}
472+
473+static DBusMessage*
474+item_property_get (GckObject *object, DBusMessage *message)
475+{
476+ const gchar *interface;
477+ const gchar *name;
478+
479+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface,
480+ DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
481+ return NULL;
482+
483+ if (!gkd_dbus_interface_match (SECRET_ITEM_INTERFACE, interface))
484+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
485+ "Object does not have properties on interface '%s'",
486+ interface);
487+
488+ return object_property_get (object, message, name);
489+}
490+
491+static DBusMessage*
492+item_property_set (GkdSecretObjects *self,
493+ GckObject *object,
494+ DBusMessage *message)
495+{
496+ DBusMessageIter iter;
497+ const char *interface;
498+ const char *name;
499+ DBusMessage *reply;
500+
501+ if (!dbus_message_has_signature (message, "ssv"))
502+ return NULL;
503+
504+ dbus_message_iter_init (message, &iter);
505+ dbus_message_iter_get_basic (&iter, &interface);
506+ dbus_message_iter_next (&iter);
507+ dbus_message_iter_get_basic (&iter, &name);
508+ dbus_message_iter_next (&iter);
509+
510+ if (!gkd_dbus_interface_match (SECRET_ITEM_INTERFACE, interface))
511+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
512+ "Object does not have properties on interface '%s'",
513+ interface);
514+
515+ reply = object_property_set (object, message, &iter, name);
516+
517+ /* Notify everyone a property changed */
518+ if (reply && dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
519+ gkd_secret_objects_emit_item_changed (self, object, name, NULL);
520+
521+ return reply;
522+}
523+
524+static DBusMessage*
525+item_property_getall (GckObject *object, DBusMessage *message)
526+{
527+ GckAttributes *attrs;
528+ DBusMessageIter iter;
529+ DBusMessageIter array;
530+ GError *error = NULL;
531+ DBusMessage *reply;
532+ const gchar *interface;
533+
534+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID))
535+ return NULL;
536+
537+ if (!gkd_dbus_interface_match (SECRET_ITEM_INTERFACE, interface))
538+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
539+ "Object does not have properties on interface '%s'",
540+ interface);
541+
542+ attrs = gck_object_get (object, NULL, &error,
543+ CKA_LABEL,
544+ CKA_G_SCHEMA,
545+ CKA_G_LOCKED,
546+ CKA_G_CREATED,
547+ CKA_G_MODIFIED,
548+ CKA_G_FIELDS,
549+ GCK_INVALID);
550+
551+ if (error != NULL)
552+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
553+ "Couldn't retrieve properties: %s",
554+ egg_error_message (error));
555+
556+ reply = dbus_message_new_method_return (message);
557+
558+ dbus_message_iter_init_append (reply, &iter);
559+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
560+ gkd_secret_property_append_all (&array, attrs);
561+ dbus_message_iter_close_container (&iter, &array);
562+ return reply;
563+}
564+
565+static DBusMessage*
566+item_method_delete (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
567+{
568+ GError *error = NULL;
569+ gchar *collection_path;
570+ gchar *item_path;
571+ DBusMessage *reply;
572+ const gchar *prompt;
573+ GckObject *collection;
574+
575+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INVALID))
576+ return NULL;
577+
578+ collection_path = collection_path_for_item (object);
579+ item_path = object_path_for_item (NULL, object);
580+
581+ if (gck_object_destroy (object, NULL, &error)) {
582+ collection = gkd_secret_objects_lookup_collection (self, NULL, collection_path);
583+ if (collection != NULL) {
584+ gkd_secret_objects_emit_item_deleted (self, collection, item_path);
585+ g_object_unref (collection);
586+ }
587+
588+ prompt = "/"; /* No prompt necessary */
589+ reply = dbus_message_new_method_return (message);
590+ dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &prompt, DBUS_TYPE_INVALID);
591+
592+ } else {
593+ if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
594+ reply = dbus_message_new_error_printf (message, SECRET_ERROR_IS_LOCKED,
595+ "Cannot delete a locked item");
596+ else
597+ reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
598+ "Couldn't delete collection: %s",
599+ egg_error_message (error));
600+
601+ g_clear_error (&error);
602+ }
603+
604+ g_free (collection_path);
605+ g_free (item_path);
606+ return reply;
607+}
608+
609+static DBusMessage*
610+item_method_get_secret (GkdSecretObjects *self, GckObject *item, DBusMessage *message)
611+{
612+ DBusError derr = DBUS_ERROR_INIT;
613+ GkdSecretSession *session;
614+ GkdSecretSecret *secret;
615+ DBusMessage *reply;
616+ DBusMessageIter iter;
617+ const char *path;
618+
619+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
620+ return NULL;
621+
622+ session = gkd_secret_service_lookup_session (self->service, path, dbus_message_get_sender (message));
623+ if (session == NULL)
624+ return dbus_message_new_error (message, SECRET_ERROR_NO_SESSION, "The session does not exist");
625+
626+ secret = gkd_secret_session_get_item_secret (session, item, &derr);
627+ if (secret == NULL)
628+ return gkd_secret_error_to_reply (message, &derr);
629+
630+ reply = dbus_message_new_method_return (message);
631+ dbus_message_iter_init_append (reply, &iter);
632+ gkd_secret_secret_append (secret, &iter);
633+ gkd_secret_secret_free (secret);
634+ return reply;
635+}
636+
637+static DBusMessage*
638+item_method_set_secret (GkdSecretObjects *self, GckObject *item, DBusMessage *message)
639+{
640+ DBusError derr = DBUS_ERROR_INIT;
641+ DBusMessageIter iter;
642+ GkdSecretSecret *secret;
643+ const char *caller;
644+
645+ if (!dbus_message_has_signature (message, "(oayays)"))
646+ return NULL;
647+ dbus_message_iter_init (message, &iter);
648+ secret = gkd_secret_secret_parse (self->service, message, &iter, &derr);
649+ if (secret == NULL)
650+ return gkd_secret_error_to_reply (message, &derr);
651+
652+ caller = dbus_message_get_sender (message);
653+ g_return_val_if_fail (caller, NULL);
654+
655+ gkd_secret_session_set_item_secret (secret->session, item, secret, &derr);
656+ gkd_secret_secret_free (secret);
657+
658+ if (dbus_error_is_set (&derr))
659+ return gkd_secret_error_to_reply (message, &derr);
660+
661+ return dbus_message_new_method_return (message);
662+}
663+
664+static DBusMessage*
665+item_message_handler (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
666+{
667+ /* org.freedesktop.Secret.Item.Delete() */
668+ if (dbus_message_is_method_call (message, SECRET_ITEM_INTERFACE, "Delete"))
669+ return item_method_delete (self, object, message);
670+
671+ /* org.freedesktop.Secret.Session.GetSecret() */
672+ else if (dbus_message_is_method_call (message, SECRET_ITEM_INTERFACE, "GetSecret"))
673+ return item_method_get_secret (self, object, message);
674+
675+ /* org.freedesktop.Secret.Session.SetSecret() */
676+ else if (dbus_message_is_method_call (message, SECRET_ITEM_INTERFACE, "SetSecret"))
677+ return item_method_set_secret (self, object, message);
678+
679+ /* org.freedesktop.DBus.Properties.Get */
680+ if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Get"))
681+ return item_property_get (object, message);
682+
683+ /* org.freedesktop.DBus.Properties.Set */
684+ else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Set"))
685+ return item_property_set (self, object, message);
686+
687+ /* org.freedesktop.DBus.Properties.GetAll */
688+ else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "GetAll"))
689+ return item_property_getall (object, message);
690+
691+ else if (dbus_message_has_interface (message, DBUS_INTERFACE_INTROSPECTABLE))
692+ return gkd_dbus_introspect_handle (message, gkd_secret_introspect_item, NULL);
693+
694+ return NULL;
695+}
696+
697+static void
698+item_cleanup_search_results (GckSession *session, GList *items,
699+ GList **locked, GList **unlocked)
700+{
701+ GError *error = NULL;
702+ gpointer value;
703+ gsize n_value;
704+ GList *l;
705+
706+ *locked = NULL;
707+ *unlocked = NULL;
708+
709+ for (l = items; l; l = g_list_next (l)) {
710+ value = gck_object_get_data (l->data, CKA_G_LOCKED, NULL, &n_value, &error);
711+ if (value == NULL) {
712+ if (!g_error_matches (error, GCK_ERROR, CKR_OBJECT_HANDLE_INVALID))
713+ g_warning ("couldn't check if item is locked: %s", egg_error_message (error));
714+ g_clear_error (&error);
715+
716+ /* Is not locked */
717+ } if (n_value == 1 && *((CK_BBOOL*)value) == CK_FALSE) {
718+ *unlocked = g_list_prepend (*unlocked, l->data);
719+
720+ /* Is locked */
721+ } else {
722+ *locked = g_list_prepend (*locked, l->data);
723+ }
724+
725+ g_free (value);
726+ }
727+
728+ *locked = g_list_reverse (*locked);
729+ *unlocked = g_list_reverse (*unlocked);
730+}
731+
732+static DBusMessage*
733+collection_property_get (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
734+{
735+ DBusMessageIter iter;
736+ DBusMessage *reply;
737+ const gchar *interface;
738+ const gchar *name;
739+
740+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface,
741+ DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
742+ return NULL;
743+
744+ if (!gkd_dbus_interface_match (SECRET_COLLECTION_INTERFACE, interface))
745+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
746+ "Object does not have properties on interface '%s'",
747+ interface);
748+
749+ /* Special case, the Items property */
750+ if (g_str_equal (name, "Items")) {
751+ reply = dbus_message_new_method_return (message);
752+ dbus_message_iter_init_append (reply, &iter);
753+ gkd_secret_objects_append_item_paths (self, dbus_message_get_path (message), &iter, message);
754+ return reply;
755+ }
756+
757+ return object_property_get (object, message, name);
758+}
759+
760+static DBusMessage*
761+collection_property_set (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
762+{
763+ DBusMessageIter iter;
764+ DBusMessage *reply;
765+ const char *interface;
766+ const char *name;
767+
768+ if (!dbus_message_has_signature (message, "ssv"))
769+ return NULL;
770+
771+ dbus_message_iter_init (message, &iter);
772+ dbus_message_iter_get_basic (&iter, &interface);
773+ dbus_message_iter_next (&iter);
774+ dbus_message_iter_get_basic (&iter, &name);
775+ dbus_message_iter_next (&iter);
776+
777+ if (!gkd_dbus_interface_match (SECRET_COLLECTION_INTERFACE, interface))
778+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
779+ "Object does not have properties on interface '%s'",
780+ interface);
781+
782+ reply = object_property_set (object, message, &iter, name);
783+
784+ /* Notify everyone a property changed */
785+ if (reply && dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
786+ gkd_secret_objects_emit_collection_changed (self, object, name, NULL);
787+
788+ return reply;
789+}
790+
791+static DBusMessage*
792+collection_property_getall (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
793+{
794+ GckAttributes *attrs;
795+ DBusMessageIter iter;
796+ DBusMessageIter array;
797+ DBusMessageIter dict;
798+ GError *error = NULL;
799+ DBusMessage *reply;
800+ const gchar *name;
801+ const gchar *interface;
802+
803+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID))
804+ return NULL;
805+
806+ if (!gkd_dbus_interface_match (SECRET_COLLECTION_INTERFACE, interface))
807+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
808+ "Object does not have properties on interface '%s'",
809+ interface);
810+
811+ attrs = gck_object_get (object, NULL, &error,
812+ CKA_LABEL,
813+ CKA_G_LOCKED,
814+ CKA_G_CREATED,
815+ CKA_G_MODIFIED,
816+ GCK_INVALID);
817+
818+ if (error != NULL)
819+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
820+ "Couldn't retrieve properties: %s",
821+ egg_error_message (error));
822+
823+ reply = dbus_message_new_method_return (message);
824+
825+ dbus_message_iter_init_append (reply, &iter);
826+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
827+
828+ /* Append all the usual properties */
829+ gkd_secret_property_append_all (&array, attrs);
830+
831+ /* Append the Items property */
832+ dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
833+ name = "Items";
834+ dbus_message_iter_append_basic (&dict, DBUS_TYPE_STRING, &name);
835+ gkd_secret_objects_append_item_paths (self, dbus_message_get_path (message), &dict, message);
836+ dbus_message_iter_close_container (&array, &dict);
837+
838+ dbus_message_iter_close_container (&iter, &array);
839+ return reply;
840+}
841+
842+static DBusMessage*
843+collection_method_search_items (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
844+{
845+ return gkd_secret_objects_handle_search_items (self, message, dbus_message_get_path (message));
846+}
847+
848+static GckObject*
849+collection_find_matching_item (GkdSecretObjects *self,
850+ GckSession *session,
851+ const gchar *identifier,
852+ const GckAttribute *fields)
853+{
854+ GckBuilder builder = GCK_BUILDER_INIT;
855+ GckObject *result = NULL;
856+ GError *error = NULL;
857+ GckObject *search;
858+ gpointer data;
859+ gsize n_data;
860+
861+ /* Find items matching the collection and fields */
862+ gck_builder_add_attribute (&builder, fields);
863+ gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
864+ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_SEARCH);
865+ gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);
866+
867+ /* Create the search object */
868+ search = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error);
869+
870+ if (error != NULL) {
871+ g_warning ("couldn't search for matching item: %s", egg_error_message (error));
872+ g_clear_error (&error);
873+ return NULL;
874+ }
875+
876+ /* Get the matched item handles, and delete the search object */
877+ data = gck_object_get_data (search, CKA_G_MATCHED, NULL, &n_data, NULL);
878+ gck_object_destroy (search, NULL, NULL);
879+ g_object_unref (search);
880+
881+ if (n_data >= sizeof (CK_OBJECT_HANDLE))
882+ result = gck_object_from_handle (session, *((CK_OBJECT_HANDLE_PTR)data));
883+
884+ g_free (data);
885+ return result;
886+}
887+
888+static gchar *
889+object_path_for_item (const gchar *base,
890+ GckObject *item)
891+{
892+ GError *error = NULL;
893+ gpointer identifier;
894+ gsize n_identifier;
895+ gchar *alloc = NULL;
896+ gchar *path = NULL;
897+
898+ if (base == NULL)
899+ base = alloc = collection_path_for_item (item);
900+
901+ identifier = gck_object_get_data (item, CKA_ID, NULL, &n_identifier, &error);
902+ if (identifier == NULL) {
903+ g_warning ("couldn't get item identifier: %s", egg_error_message (error));
904+ g_clear_error (&error);
905+ path = NULL;
906+
907+ } else {
908+ path = gkd_secret_util_build_path (base, identifier, n_identifier);
909+ g_free (identifier);
910+ }
911+
912+ g_free (alloc);
913+ return path;
914+}
915+
916+static gchar *
917+collection_path_for_item (GckObject *item)
918+{
919+ GError *error = NULL;
920+ gpointer identifier;
921+ gsize n_identifier;
922+ gchar *path = NULL;
923+
924+ identifier = gck_object_get_data (item, CKA_G_COLLECTION, NULL, &n_identifier, &error);
925+ if (!identifier) {
926+ g_warning ("couldn't get item collection identifier: %s", egg_error_message (error));
927+ g_clear_error (&error);
928+ return NULL;
929+ }
930+
931+ path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
932+ g_free (identifier);
933+ return path;
934+}
935+
936+static gchar *
937+object_path_for_collection (GckObject *collection)
938+{
939+ GError *error = NULL;
940+ gpointer identifier;
941+ gsize n_identifier;
942+ gchar *path = NULL;
943+
944+ identifier = gck_object_get_data (collection, CKA_ID, NULL, &n_identifier, &error);
945+ if (identifier == NULL) {
946+ g_warning ("couldn't get collection identifier: %s", egg_error_message (error));
947+ g_clear_error (&error);
948+ path = NULL;
949+
950+ } else {
951+ path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
952+ g_free (identifier);
953+ }
954+
955+ return path;
956+}
957+
958+static DBusMessage*
959+collection_method_create_item (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
960+{
961+ GckBuilder builder = GCK_BUILDER_INIT;
962+ GckSession *pkcs11_session = NULL;
963+ DBusError derr = DBUS_ERROR_INIT;
964+ GkdSecretSecret *secret = NULL;
965+ dbus_bool_t replace = FALSE;
966+ GckAttributes *attrs = NULL;
967+ const GckAttribute *fields;
968+ DBusMessageIter iter, array;
969+ GckObject *item = NULL;
970+ const gchar *prompt;
971+ const gchar *base;
972+ GError *error = NULL;
973+ DBusMessage *reply = NULL;
974+ gchar *path = NULL;
975+ gchar *identifier;
976+ gboolean created = FALSE;
977+
978+ /* Parse the message */
979+ if (!dbus_message_has_signature (message, "a{sv}(oayays)b"))
980+ return NULL;
981+ if (!dbus_message_iter_init (message, &iter))
982+ g_return_val_if_reached (NULL);
983+ dbus_message_iter_recurse (&iter, &array);
984+ if (!gkd_secret_property_parse_all (&array, SECRET_ITEM_INTERFACE, &builder)) {
985+ reply = dbus_message_new_error (message, DBUS_ERROR_INVALID_ARGS,
986+ "Invalid properties argument");
987+ goto cleanup;
988+ }
989+ dbus_message_iter_next (&iter);
990+ secret = gkd_secret_secret_parse (self->service, message, &iter, &derr);
991+ if (secret == NULL) {
992+ reply = gkd_secret_error_to_reply (message, &derr);
993+ goto cleanup;
994+ }
995+ dbus_message_iter_next (&iter);
996+ dbus_message_iter_get_basic (&iter, &replace);
997+
998+ base = dbus_message_get_path (message);
999+ if (!parse_object_path (self, base, &identifier, NULL))
1000+ g_return_val_if_reached (NULL);
1001+ g_return_val_if_fail (identifier, NULL);
1002+
1003+ pkcs11_session = gck_object_get_session (object);
1004+ g_return_val_if_fail (pkcs11_session, NULL);
1005+
1006+ attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
1007+
1008+ if (replace) {
1009+ fields = gck_attributes_find (attrs, CKA_G_FIELDS);
1010+ if (fields)
1011+ item = collection_find_matching_item (self, pkcs11_session, identifier, fields);
1012+ }
1013+
1014+ /* Replace the item */
1015+ if (item) {
1016+ if (!gck_object_set (item, attrs, NULL, &error))
1017+ goto cleanup;
1018+
1019+ /* Create a new item */
1020+ } else {
1021+ gck_builder_add_all (&builder, attrs);
1022+ gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
1023+ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
1024+ item = gck_session_create_object (pkcs11_session, gck_builder_end (&builder), NULL, &error);
1025+ if (item == NULL)
1026+ goto cleanup;
1027+ created = TRUE;
1028+ }
1029+
1030+ /* Set the secret */
1031+ if (!gkd_secret_session_set_item_secret (secret->session, item, secret, &derr)) {
1032+ if (created) /* If we created, then try to destroy on failure */
1033+ gck_object_destroy (item, NULL, NULL);
1034+ goto cleanup;
1035+ }
1036+
1037+ path = object_path_for_item (base, item);
1038+ gkd_secret_objects_emit_item_created (self, object, item);
1039+
1040+ /* Build up the item identifier */
1041+ reply = dbus_message_new_method_return (message);
1042+ dbus_message_iter_init_append (reply, &iter);
1043+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_OBJECT_PATH, &path);
1044+ prompt = "/";
1045+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_OBJECT_PATH, &prompt);
1046+
1047+cleanup:
1048+ if (error) {
1049+ if (!reply) {
1050+ if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
1051+ reply = dbus_message_new_error_printf (message, SECRET_ERROR_IS_LOCKED,
1052+ "Cannot create an item in a locked collection");
1053+ else
1054+ reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
1055+ "Couldn't create item: %s", egg_error_message (error));
1056+ }
1057+ g_clear_error (&error);
1058+ }
1059+
1060+ if (dbus_error_is_set (&derr)) {
1061+ if (!reply)
1062+ reply = dbus_message_new_error (message, derr.name, derr.message);
1063+ dbus_error_free (&derr);
1064+ }
1065+
1066+ gkd_secret_secret_free (secret);
1067+ gck_attributes_unref (attrs);
1068+ if (item)
1069+ g_object_unref (item);
1070+ if (pkcs11_session)
1071+ g_object_unref (pkcs11_session);
1072+ g_free (path);
1073+
1074+ return reply;
1075+}
1076+
1077+static DBusMessage*
1078+collection_method_delete (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
1079+{
1080+ GError *error = NULL;
1081+ DBusMessage *reply;
1082+ const gchar *prompt;
1083+ gchar *path;
1084+
1085+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INVALID))
1086+ return NULL;
1087+
1088+ path = object_path_for_collection (object);
1089+ g_return_val_if_fail (path != NULL, NULL);
1090+
1091+ if (!gck_object_destroy (object, NULL, &error)) {
1092+ reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
1093+ "Couldn't delete collection: %s",
1094+ egg_error_message (error));
1095+ g_clear_error (&error);
1096+ g_free (path);
1097+ return reply;
1098+ }
1099+
1100+ /* Notify the callers that a collection was deleted */
1101+ gkd_secret_service_emit_collection_deleted (self->service, path);
1102+ g_free (path);
1103+
1104+ prompt = "/";
1105+ reply = dbus_message_new_method_return (message);
1106+ dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &prompt, DBUS_TYPE_INVALID);
1107+ return reply;
1108+}
1109+
1110+static void
1111+on_each_path_append_to_array (GkdSecretObjects *self,
1112+ const gchar *path,
1113+ GckObject *object,
1114+ gpointer user_data)
1115+{
1116+ GPtrArray *array = user_data;
1117+ g_ptr_array_add (array, g_strdup (path));
1118+}
1119+
1120+static DBusMessage *
1121+collection_introspect (GkdSecretObjects *self,
1122+ GckObject *object,
1123+ DBusMessage *message)
1124+{
1125+ GPtrArray *names;
1126+ DBusMessage *reply;
1127+
1128+ names = g_ptr_array_new_with_free_func (g_free);
1129+ gkd_secret_objects_foreach_item (self, message, dbus_message_get_path (message),
1130+ on_each_path_append_to_array, names);
1131+ g_ptr_array_add (names, NULL);
1132+
1133+ reply = gkd_dbus_introspect_handle (message, gkd_secret_introspect_collection,
1134+ (const gchar **)names->pdata);
1135+
1136+ g_ptr_array_unref (names);
1137+ return reply;
1138+}
1139+
1140+static DBusMessage*
1141+collection_message_handler (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
1142+{
1143+ /* org.freedesktop.Secret.Collection.Delete() */
1144+ if (dbus_message_is_method_call (message, SECRET_COLLECTION_INTERFACE, "Delete"))
1145+ return collection_method_delete (self, object, message);
1146+
1147+ /* org.freedesktop.Secret.Collection.SearchItems() */
1148+ if (dbus_message_is_method_call (message, SECRET_COLLECTION_INTERFACE, "SearchItems"))
1149+ return collection_method_search_items (self, object, message);
1150+
1151+ /* org.freedesktop.Secret.Collection.CreateItem() */
1152+ if (dbus_message_is_method_call (message, SECRET_COLLECTION_INTERFACE, "CreateItem"))
1153+ return collection_method_create_item (self, object, message);
1154+
1155+ /* org.freedesktop.DBus.Properties.Get() */
1156+ if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Get"))
1157+ return collection_property_get (self, object, message);
1158+
1159+ /* org.freedesktop.DBus.Properties.Set() */
1160+ else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Set"))
1161+ return collection_property_set (self, object, message);
1162+
1163+ /* org.freedesktop.DBus.Properties.GetAll() */
1164+ else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "GetAll"))
1165+ return collection_property_getall (self, object, message);
1166+
1167+ /* org.freedesktop.DBus.Introspectable.Introspect() */
1168+ else if (dbus_message_has_interface (message, DBUS_INTERFACE_INTROSPECTABLE))
1169+ return collection_introspect (self, object, message);
1170+
1171+ return NULL;
1172+}
1173+
1174+/* -----------------------------------------------------------------------------
1175+ * OBJECT
1176+ */
1177+
1178+static GObject*
1179+gkd_secret_objects_constructor (GType type, guint n_props, GObjectConstructParam *props)
1180+{
1181+ GkdSecretObjects *self = GKD_SECRET_OBJECTS (G_OBJECT_CLASS (gkd_secret_objects_parent_class)->constructor(type, n_props, props));
1182+
1183+ g_return_val_if_fail (self, NULL);
1184+ g_return_val_if_fail (self->pkcs11_slot, NULL);
1185+ g_return_val_if_fail (self->service, NULL);
1186+
1187+ return G_OBJECT (self);
1188+}
1189+
1190+static void
1191+gkd_secret_objects_init (GkdSecretObjects *self)
1192+{
1193+
1194+}
1195+
1196+static void
1197+gkd_secret_objects_dispose (GObject *obj)
1198+{
1199+ GkdSecretObjects *self = GKD_SECRET_OBJECTS (obj);
1200+
1201+ if (self->pkcs11_slot) {
1202+ g_object_unref (self->pkcs11_slot);
1203+ self->pkcs11_slot = NULL;
1204+ }
1205+
1206+ if (self->service) {
1207+ g_object_remove_weak_pointer (G_OBJECT (self->service),
1208+ (gpointer*)&(self->service));
1209+ self->service = NULL;
1210+ }
1211+
1212+ G_OBJECT_CLASS (gkd_secret_objects_parent_class)->dispose (obj);
1213+}
1214+
1215+static void
1216+gkd_secret_objects_finalize (GObject *obj)
1217+{
1218+ GkdSecretObjects *self = GKD_SECRET_OBJECTS (obj);
1219+
1220+ g_assert (!self->pkcs11_slot);
1221+ g_assert (!self->service);
1222+
1223+ G_OBJECT_CLASS (gkd_secret_objects_parent_class)->finalize (obj);
1224+}
1225+
1226+static void
1227+gkd_secret_objects_set_property (GObject *obj, guint prop_id, const GValue *value,
1228+ GParamSpec *pspec)
1229+{
1230+ GkdSecretObjects *self = GKD_SECRET_OBJECTS (obj);
1231+
1232+ switch (prop_id) {
1233+ case PROP_PKCS11_SLOT:
1234+ g_return_if_fail (!self->pkcs11_slot);
1235+ self->pkcs11_slot = g_value_dup_object (value);
1236+ g_return_if_fail (self->pkcs11_slot);
1237+ break;
1238+ case PROP_SERVICE:
1239+ g_return_if_fail (!self->service);
1240+ self->service = g_value_get_object (value);
1241+ g_return_if_fail (self->service);
1242+ g_object_add_weak_pointer (G_OBJECT (self->service),
1243+ (gpointer*)&(self->service));
1244+ break;
1245+ default:
1246+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1247+ break;
1248+ }
1249+}
1250+
1251+static void
1252+gkd_secret_objects_get_property (GObject *obj, guint prop_id, GValue *value,
1253+ GParamSpec *pspec)
1254+{
1255+ GkdSecretObjects *self = GKD_SECRET_OBJECTS (obj);
1256+
1257+ switch (prop_id) {
1258+ case PROP_PKCS11_SLOT:
1259+ g_value_set_object (value, gkd_secret_objects_get_pkcs11_slot (self));
1260+ break;
1261+ case PROP_SERVICE:
1262+ g_value_set_object (value, self->service);
1263+ break;
1264+ default:
1265+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1266+ break;
1267+ }
1268+}
1269+
1270+static void
1271+gkd_secret_objects_class_init (GkdSecretObjectsClass *klass)
1272+{
1273+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1274+
1275+ gobject_class->constructor = gkd_secret_objects_constructor;
1276+ gobject_class->dispose = gkd_secret_objects_dispose;
1277+ gobject_class->finalize = gkd_secret_objects_finalize;
1278+ gobject_class->set_property = gkd_secret_objects_set_property;
1279+ gobject_class->get_property = gkd_secret_objects_get_property;
1280+
1281+ g_object_class_install_property (gobject_class, PROP_PKCS11_SLOT,
1282+ g_param_spec_object ("pkcs11-slot", "Pkcs11 Slot", "PKCS#11 slot that we use for secrets",
1283+ GCK_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1284+
1285+ g_object_class_install_property (gobject_class, PROP_SERVICE,
1286+ g_param_spec_object ("service", "Service", "Service which owns this objects",
1287+ GKD_SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1288+}
1289+
1290+/* -----------------------------------------------------------------------------
1291+ * PUBLIC
1292+ */
1293+
1294+GckSlot*
1295+gkd_secret_objects_get_pkcs11_slot (GkdSecretObjects *self)
1296+{
1297+ g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1298+ return self->pkcs11_slot;
1299+}
1300+
1301+DBusMessage*
1302+gkd_secret_objects_dispatch (GkdSecretObjects *self, DBusMessage *message)
1303+{
1304+ GckBuilder builder = GCK_BUILDER_INIT;
1305+ DBusMessage *reply = NULL;
1306+ GError *error = NULL;
1307+ GList *objects;
1308+ GckSession *session;
1309+ gchar *c_ident;
1310+ gchar *i_ident;
1311+ gboolean is_item;
1312+ const char *path;
1313+
1314+ g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1315+ g_return_val_if_fail (message, NULL);
1316+
1317+ path = dbus_message_get_path (message);
1318+ g_return_val_if_fail (path, NULL);
1319+
1320+ if (!parse_object_path (self, path, &c_ident, &i_ident) || !c_ident)
1321+ return gkd_secret_error_no_such_object (message);
1322+
1323+ /* The session we're using to access the object */
1324+ session = gkd_secret_service_get_pkcs11_session (self->service, dbus_message_get_sender (message));
1325+ g_return_val_if_fail (session, NULL);
1326+
1327+ if (i_ident) {
1328+ is_item = TRUE;
1329+ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
1330+ gck_builder_add_string (&builder, CKA_G_COLLECTION, c_ident);
1331+ gck_builder_add_string (&builder, CKA_ID, i_ident);
1332+ } else {
1333+ is_item = FALSE;
1334+ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
1335+ gck_builder_add_string (&builder, CKA_ID, c_ident);
1336+ }
1337+
1338+ objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1339+
1340+ g_free (c_ident);
1341+ g_free (i_ident);
1342+
1343+ if (error != NULL) {
1344+ g_warning ("couldn't lookup object: %s: %s", path, egg_error_message (error));
1345+ g_clear_error (&error);
1346+ }
1347+
1348+ if (!objects)
1349+ return gkd_secret_error_no_such_object (message);
1350+
1351+ if (is_item)
1352+ reply = item_message_handler (self, objects->data, message);
1353+ else
1354+ reply = collection_message_handler (self, objects->data, message);
1355+
1356+ gck_list_unref_free (objects);
1357+ return reply;
1358+}
1359+
1360+GckObject*
1361+gkd_secret_objects_lookup_collection (GkdSecretObjects *self, const gchar *caller,
1362+ const gchar *path)
1363+{
1364+ GckBuilder builder = GCK_BUILDER_INIT;
1365+ GckObject *object = NULL;
1366+ GError *error = NULL;
1367+ GList *objects;
1368+ GckSession *session;
1369+ gchar *identifier;
1370+
1371+ g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1372+ g_return_val_if_fail (path, NULL);
1373+
1374+ if (!parse_object_path (self, path, &identifier, NULL))
1375+ return NULL;
1376+
1377+ /* The session we're using to access the object */
1378+ if (caller == NULL)
1379+ session = gkd_secret_service_internal_pkcs11_session (self->service);
1380+ else
1381+ session = gkd_secret_service_get_pkcs11_session (self->service, caller);
1382+ g_return_val_if_fail (session, NULL);
1383+
1384+ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
1385+ gck_builder_add_string (&builder, CKA_ID, identifier);
1386+
1387+ objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1388+
1389+ g_free (identifier);
1390+
1391+ if (error != NULL) {
1392+ g_warning ("couldn't lookup collection: %s: %s", path, egg_error_message (error));
1393+ g_clear_error (&error);
1394+ }
1395+
1396+ if (objects)
1397+ object = g_object_ref (objects->data);
1398+
1399+ gck_list_unref_free (objects);
1400+ return object;
1401+}
1402+
1403+GckObject*
1404+gkd_secret_objects_lookup_item (GkdSecretObjects *self, const gchar *caller,
1405+ const gchar *path)
1406+{
1407+ GckBuilder builder = GCK_BUILDER_INIT;
1408+ GckObject *object = NULL;
1409+ GError *error = NULL;
1410+ GList *objects;
1411+ GckSession *session;
1412+ gchar *collection;
1413+ gchar *identifier;
1414+
1415+ g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1416+ g_return_val_if_fail (caller, NULL);
1417+ g_return_val_if_fail (path, NULL);
1418+
1419+ if (!parse_object_path (self, path, &collection, &identifier))
1420+ return NULL;
1421+
1422+ /* The session we're using to access the object */
1423+ session = gkd_secret_service_get_pkcs11_session (self->service, caller);
1424+ g_return_val_if_fail (session, NULL);
1425+
1426+ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
1427+ gck_builder_add_string (&builder, CKA_ID, identifier);
1428+ gck_builder_add_string (&builder, CKA_G_COLLECTION, collection);
1429+
1430+ objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1431+
1432+ g_free (identifier);
1433+ g_free (collection);
1434+
1435+ if (error != NULL) {
1436+ g_warning ("couldn't lookup item: %s: %s", path, egg_error_message (error));
1437+ g_clear_error (&error);
1438+ }
1439+
1440+ if (objects)
1441+ object = g_object_ref (objects->data);
1442+
1443+ gck_list_unref_free (objects);
1444+ return object;
1445+}
1446+
1447+static void
1448+objects_foreach_item (GkdSecretObjects *self,
1449+ GList *items,
1450+ const gchar *base,
1451+ GkdSecretObjectsForeach callback,
1452+ gpointer user_data)
1453+{
1454+ gchar *path;
1455+ GList *l;
1456+
1457+ for (l = items; l; l = g_list_next (l)) {
1458+ path = object_path_for_item (base, l->data);
1459+ (callback) (self, path, l->data, user_data);
1460+ g_free (path);
1461+ }
1462+}
1463+
1464+void
1465+gkd_secret_objects_foreach_item (GkdSecretObjects *self,
1466+ DBusMessage *message,
1467+ const gchar *base,
1468+ GkdSecretObjectsForeach callback,
1469+ gpointer user_data)
1470+{
1471+ GckBuilder builder = GCK_BUILDER_INIT;
1472+ GckSession *session;
1473+ GError *error = NULL;
1474+ gchar *identifier;
1475+ GList *items;
1476+
1477+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1478+ g_return_if_fail (base != NULL);
1479+ g_return_if_fail (callback != NULL);
1480+
1481+ /* The session we're using to access the object */
1482+ if (message == NULL) {
1483+ session = gkd_secret_service_internal_pkcs11_session (self->service);
1484+ } else {
1485+ session = gkd_secret_service_get_pkcs11_session (self->service,
1486+ dbus_message_get_sender (message));
1487+ }
1488+
1489+ if (!parse_object_path (self, base, &identifier, NULL))
1490+ g_return_if_reached ();
1491+
1492+ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
1493+ gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
1494+
1495+ items = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1496+
1497+ if (error == NULL) {
1498+ objects_foreach_item (self, items, base, callback, user_data);
1499+
1500+ } else {
1501+ g_warning ("couldn't lookup items in '%s' collection: %s", identifier, egg_error_message (error));
1502+ g_clear_error (&error);
1503+ }
1504+
1505+ gck_list_unref_free (items);
1506+ g_free (identifier);
1507+}
1508+
1509+static void
1510+on_object_path_append_to_iter (GkdSecretObjects *self,
1511+ const gchar *path,
1512+ GckObject *object,
1513+ gpointer user_data)
1514+{
1515+ DBusMessageIter *array = user_data;
1516+ dbus_message_iter_append_basic (array, DBUS_TYPE_OBJECT_PATH, &path);
1517+}
1518+
1519+void
1520+gkd_secret_objects_append_item_paths (GkdSecretObjects *self,
1521+ const gchar *base,
1522+ DBusMessageIter *iter,
1523+ DBusMessage *message)
1524+{
1525+ DBusMessageIter variant;
1526+ DBusMessageIter array;
1527+
1528+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1529+ g_return_if_fail (base);
1530+ g_return_if_fail (iter);
1531+
1532+
1533+ dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "ao", &variant);
1534+ dbus_message_iter_open_container (&variant, DBUS_TYPE_ARRAY, "o", &array);
1535+
1536+ gkd_secret_objects_foreach_item (self, message, base, on_object_path_append_to_iter, &array);
1537+
1538+ dbus_message_iter_close_container (&variant, &array);
1539+ dbus_message_iter_close_container (iter, &variant);
1540+}
1541+
1542+void
1543+gkd_secret_objects_foreach_collection (GkdSecretObjects *self,
1544+ DBusMessage *message,
1545+ GkdSecretObjectsForeach callback,
1546+ gpointer user_data)
1547+{
1548+ GckBuilder builder = GCK_BUILDER_INIT;
1549+ GckSession *session;
1550+ GError *error = NULL;
1551+ GList *collections, *l;
1552+ gpointer identifier;
1553+ gsize n_identifier;
1554+ gchar *path;
1555+
1556+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1557+ g_return_if_fail (callback);
1558+
1559+ /* The session we're using to access the object */
1560+ if (message == NULL) {
1561+ session = gkd_secret_service_internal_pkcs11_session (self->service);
1562+ } else {
1563+ session = gkd_secret_service_get_pkcs11_session (self->service,
1564+ dbus_message_get_sender (message));
1565+ }
1566+
1567+ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
1568+
1569+ collections = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1570+
1571+ if (error != NULL) {
1572+ g_warning ("couldn't lookup collections: %s", egg_error_message (error));
1573+ g_clear_error (&error);
1574+ return;
1575+ }
1576+
1577+ for (l = collections; l; l = g_list_next (l)) {
1578+
1579+ identifier = gck_object_get_data (l->data, CKA_ID, NULL, &n_identifier, &error);
1580+ if (identifier == NULL) {
1581+ g_warning ("couldn't get collection identifier: %s", egg_error_message (error));
1582+ g_clear_error (&error);
1583+ continue;
1584+ }
1585+
1586+ path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
1587+ g_free (identifier);
1588+
1589+ (callback) (self, path, l->data, user_data);
1590+ g_free (path);
1591+ }
1592+
1593+ gck_list_unref_free (collections);
1594+}
1595+
1596+void
1597+gkd_secret_objects_append_collection_paths (GkdSecretObjects *self,
1598+ DBusMessageIter *iter,
1599+ DBusMessage *message)
1600+{
1601+ DBusMessageIter variant;
1602+ DBusMessageIter array;
1603+
1604+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1605+ g_return_if_fail (iter != NULL);
1606+
1607+ dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "ao", &variant);
1608+ dbus_message_iter_open_container (&variant, DBUS_TYPE_ARRAY, "o", &array);
1609+
1610+ gkd_secret_objects_foreach_collection (self, message, on_object_path_append_to_iter, &array);
1611+
1612+ dbus_message_iter_close_container (&variant, &array);
1613+ dbus_message_iter_close_container (iter, &variant);
1614+}
1615+
1616+DBusMessage*
1617+gkd_secret_objects_handle_search_items (GkdSecretObjects *self, DBusMessage *message,
1618+ const gchar *base)
1619+{
1620+ GckBuilder builder = GCK_BUILDER_INIT;
1621+ DBusMessageIter iter;
1622+ DBusMessageIter array;
1623+ GckObject *search;
1624+ GckSession *session;
1625+ DBusMessage *reply;
1626+ GError *error = NULL;
1627+ gchar *identifier;
1628+ gpointer data;
1629+ gsize n_data;
1630+ GList *locked, *unlocked;
1631+ GList *items;
1632+
1633+ g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1634+ g_return_val_if_fail (message, NULL);
1635+
1636+ if (!dbus_message_has_signature (message, "a{ss}"))
1637+ return NULL;
1638+
1639+ dbus_message_iter_init (message, &iter);
1640+ if (!gkd_secret_property_parse_fields (&iter, &builder)) {
1641+ gck_builder_clear (&builder);
1642+ return dbus_message_new_error (message, DBUS_ERROR_FAILED,
1643+ "Invalid data in attributes argument");
1644+ }
1645+
1646+ if (base != NULL) {
1647+ if (!parse_object_path (self, base, &identifier, NULL))
1648+ g_return_val_if_reached (NULL);
1649+ gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
1650+ g_free (identifier);
1651+ }
1652+
1653+ gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_SEARCH);
1654+ gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);
1655+
1656+ /* The session we're using to access the object */
1657+ session = gkd_secret_service_get_pkcs11_session (self->service, dbus_message_get_sender (message));
1658+ g_return_val_if_fail (session, NULL);
1659+
1660+ /* Create the search object */
1661+ search = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error);
1662+
1663+ if (error != NULL) {
1664+ reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
1665+ "Couldn't search for items: %s",
1666+ egg_error_message (error));
1667+ g_clear_error (&error);
1668+ return reply;
1669+ }
1670+
1671+ /* Get the matched item handles, and delete the search object */
1672+ data = gck_object_get_data (search, CKA_G_MATCHED, NULL, &n_data, &error);
1673+ gck_object_destroy (search, NULL, NULL);
1674+ g_object_unref (search);
1675+
1676+ if (error != NULL) {
1677+ reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
1678+ "Couldn't retrieve matched items: %s",
1679+ egg_error_message (error));
1680+ g_clear_error (&error);
1681+ return reply;
1682+ }
1683+
1684+ /* Build a list of object handles */
1685+ items = gck_objects_from_handle_array (session, data, n_data / sizeof (CK_OBJECT_HANDLE));
1686+ g_free (data);
1687+
1688+ /* Filter out the locked items */
1689+ item_cleanup_search_results (session, items, &locked, &unlocked);
1690+
1691+ /* Prepare the reply message */
1692+ reply = dbus_message_new_method_return (message);
1693+ dbus_message_iter_init_append (reply, &iter);
1694+
1695+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
1696+ objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_iter, &array);
1697+ dbus_message_iter_close_container (&iter, &array);
1698+
1699+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
1700+ objects_foreach_item (self, locked, NULL, on_object_path_append_to_iter, &array);
1701+ dbus_message_iter_close_container (&iter, &array);
1702+
1703+ g_list_free (locked);
1704+ g_list_free (unlocked);
1705+ gck_list_unref_free (items);
1706+
1707+ return reply;
1708+}
1709+
1710+DBusMessage*
1711+gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self, DBusMessage *message)
1712+{
1713+ DBusError derr = DBUS_ERROR_INIT;
1714+ GkdSecretSession *session;
1715+ GkdSecretSecret *secret;
1716+ DBusMessage *reply;
1717+ GckObject *item;
1718+ DBusMessageIter iter, array, dict;
1719+ const char *session_path;
1720+ const char *caller;
1721+ char **paths;
1722+ int n_paths, i;
1723+
1724+ if (!dbus_message_get_args (message, NULL,
1725+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &paths, &n_paths,
1726+ DBUS_TYPE_OBJECT_PATH, &session_path,
1727+ DBUS_TYPE_INVALID))
1728+ return NULL;
1729+
1730+ caller = dbus_message_get_sender (message);
1731+ g_return_val_if_fail (caller, NULL);
1732+
1733+ session = gkd_secret_service_lookup_session (self->service, session_path,
1734+ dbus_message_get_sender (message));
1735+ if (session == NULL)
1736+ return dbus_message_new_error (message, SECRET_ERROR_NO_SESSION, "The session does not exist");
1737+
1738+ reply = dbus_message_new_method_return (message);
1739+ dbus_message_iter_init_append (reply, &iter);
1740+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{o(oayays)}", &array);
1741+
1742+ for (i = 0; i < n_paths; ++i) {
1743+
1744+ /* Try to find the item, if it doesn't exist, just ignore */
1745+ item = gkd_secret_objects_lookup_item (self, caller, paths[i]);
1746+ if (!item)
1747+ continue;
1748+
1749+ secret = gkd_secret_session_get_item_secret (session, item, &derr);
1750+ g_object_unref (item);
1751+
1752+ if (secret == NULL) {
1753+ /* We ignore is locked, and just leave out from response */
1754+ if (dbus_error_has_name (&derr, SECRET_ERROR_IS_LOCKED)) {
1755+ dbus_error_free (&derr);
1756+ continue;
1757+
1758+ /* All other errors stop the operation */
1759+ } else {
1760+ dbus_message_unref (reply);
1761+ reply = dbus_message_new_error (message, derr.name, derr.message);
1762+ dbus_error_free (&derr);
1763+ break;
1764+ }
1765+ }
1766+
1767+ dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
1768+ dbus_message_iter_append_basic (&dict, DBUS_TYPE_OBJECT_PATH, &(paths[i]));
1769+ gkd_secret_secret_append (secret, &dict);
1770+ gkd_secret_secret_free (secret);
1771+ dbus_message_iter_close_container (&array, &dict);
1772+ }
1773+
1774+ if (i == n_paths)
1775+ dbus_message_iter_close_container (&iter, &array);
1776+ dbus_free_string_array (paths);
1777+
1778+ return reply;
1779+}
1780+
1781+static void
1782+on_each_item_emit_locked (GkdSecretObjects *self,
1783+ const gchar *path,
1784+ GckObject *object,
1785+ gpointer user_data)
1786+{
1787+ gkd_secret_objects_emit_item_changed (self, object, "Locked", NULL);
1788+}
1789+
1790+void
1791+gkd_secret_objects_emit_collection_locked (GkdSecretObjects *self,
1792+ GckObject *collection)
1793+{
1794+ const gchar *collection_path;
1795+
1796+ collection_path = object_path_for_collection (collection);
1797+ gkd_secret_objects_foreach_item (self, NULL, collection_path,
1798+ on_each_item_emit_locked, NULL);
1799+
1800+ gkd_secret_objects_emit_collection_changed (self, collection, "Locked", NULL);
1801+}
1802+
1803+static void
1804+emit_object_properties_changed (GkdSecretObjects *self,
1805+ GckObject *object,
1806+ const gchar *path,
1807+ const gchar *iface,
1808+ va_list va)
1809+{
1810+ gchar *collection_path;
1811+ const gchar *propname;
1812+ DBusMessage *message;
1813+ DBusMessageIter iter;
1814+ DBusMessageIter array;
1815+ DBusMessageIter dict;
1816+ CK_ATTRIBUTE_TYPE type;
1817+ GckAttributes *attrs;
1818+ GError *error = NULL;
1819+ gboolean items = FALSE;
1820+ GArray *types;
1821+
1822+ types = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE_TYPE));
1823+ while ((propname = va_arg (va, const gchar *)) != NULL) {
1824+
1825+ /* Special case the Items property */
1826+ if (g_str_equal (propname, "Items")) {
1827+ items = TRUE;
1828+ continue;
1829+ }
1830+
1831+ if (gkd_secret_property_get_type (propname, &type))
1832+ g_array_append_val (types, type);
1833+ else
1834+ g_warning ("invalid property: %s", propname);
1835+ }
1836+
1837+ attrs = gck_object_get_full (object, (CK_ATTRIBUTE_TYPE *)types->data,
1838+ types->len, NULL, &error);
1839+ g_array_free (types, TRUE);
1840+
1841+ if (error != NULL) {
1842+ g_warning ("couldn't retrieve properties: %s", egg_error_message (error));
1843+ return;
1844+ }
1845+
1846+ message = dbus_message_new_signal (path, DBUS_INTERFACE_PROPERTIES,
1847+ "PropertiesChanged");
1848+
1849+ dbus_message_iter_init_append (message, &iter);
1850+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &iface);
1851+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
1852+ gkd_secret_property_append_all (&array, attrs);
1853+
1854+ /* Append the Items property */
1855+ if (items) {
1856+ collection_path = object_path_for_collection (object);
1857+ dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
1858+ propname = "Items";
1859+ dbus_message_iter_append_basic (&dict, DBUS_TYPE_STRING, &propname);
1860+ gkd_secret_objects_append_item_paths (self, collection_path, &dict, NULL);
1861+ dbus_message_iter_close_container (&array, &dict);
1862+ g_free (collection_path);
1863+ }
1864+
1865+ dbus_message_iter_close_container (&iter, &array);
1866+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &array);
1867+ dbus_message_iter_close_container (&iter, &array);
1868+
1869+ if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
1870+ message, NULL))
1871+ g_return_if_reached ();
1872+ dbus_message_unref (message);
1873+
1874+ gck_attributes_unref (attrs);
1875+}
1876+
1877+void
1878+gkd_secret_objects_emit_collection_changed (GkdSecretObjects *self,
1879+ GckObject *collection,
1880+ ...)
1881+{
1882+ DBusMessage *message;
1883+ gchar *collection_path;
1884+ va_list va;
1885+
1886+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1887+ g_return_if_fail (GCK_OBJECT (collection));
1888+
1889+ collection_path = object_path_for_collection (collection);
1890+
1891+ message = dbus_message_new_signal (SECRET_SERVICE_PATH,
1892+ SECRET_SERVICE_INTERFACE,
1893+ "CollectionChanged");
1894+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &collection_path,
1895+ DBUS_TYPE_INVALID);
1896+
1897+ if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
1898+ message, NULL))
1899+ g_return_if_reached ();
1900+
1901+ dbus_message_unref (message);
1902+
1903+ va_start (va, collection);
1904+ emit_object_properties_changed (self, collection, collection_path,
1905+ SECRET_COLLECTION_INTERFACE, va);
1906+ va_end (va);
1907+
1908+ g_free (collection_path);
1909+}
1910+
1911+void
1912+gkd_secret_objects_emit_item_created (GkdSecretObjects *self,
1913+ GckObject *collection,
1914+ GckObject *item)
1915+{
1916+ DBusMessage *message;
1917+ gchar *collection_path;
1918+ gchar *item_path;
1919+
1920+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1921+ g_return_if_fail (GCK_OBJECT (collection));
1922+ g_return_if_fail (GCK_OBJECT (item));
1923+
1924+ collection_path = object_path_for_collection (collection);
1925+ item_path = object_path_for_item (collection_path, item);
1926+
1927+ message = dbus_message_new_signal (collection_path,
1928+ SECRET_COLLECTION_INTERFACE,
1929+ "ItemCreated");
1930+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &item_path,
1931+ DBUS_TYPE_INVALID);
1932+
1933+ if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
1934+ message, NULL))
1935+ g_return_if_reached ();
1936+
1937+ dbus_message_unref (message);
1938+
1939+ gkd_secret_objects_emit_collection_changed (self, collection, "Items", NULL);
1940+
1941+ g_free (item_path);
1942+ g_free (collection_path);
1943+}
1944+
1945+void
1946+gkd_secret_objects_emit_item_changed (GkdSecretObjects *self,
1947+ GckObject *item,
1948+ ...)
1949+{
1950+ DBusMessage *message;
1951+ gchar *collection_path;
1952+ gchar *item_path;
1953+ va_list va;
1954+
1955+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1956+ g_return_if_fail (GCK_OBJECT (item));
1957+
1958+ collection_path = collection_path_for_item (item);
1959+ item_path = object_path_for_item (collection_path, item);
1960+
1961+ message = dbus_message_new_signal (collection_path,
1962+ SECRET_COLLECTION_INTERFACE,
1963+ "ItemChanged");
1964+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &item_path,
1965+ DBUS_TYPE_INVALID);
1966+
1967+ if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
1968+ message, NULL))
1969+ g_return_if_reached ();
1970+
1971+ dbus_message_unref (message);
1972+
1973+ va_start (va, item);
1974+ emit_object_properties_changed (self, item, item_path,
1975+ SECRET_ITEM_INTERFACE, va);
1976+ va_end (va);
1977+
1978+ g_free (item_path);
1979+ g_free (collection_path);
1980+}
1981+
1982+void
1983+gkd_secret_objects_emit_item_deleted (GkdSecretObjects *self,
1984+ GckObject *collection,
1985+ const gchar *item_path)
1986+{
1987+ DBusMessage *message;
1988+ gchar *collection_path;
1989+
1990+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1991+ g_return_if_fail (GCK_OBJECT (collection));
1992+ g_return_if_fail (item_path != NULL);
1993+
1994+ collection_path = object_path_for_collection (collection);
1995+
1996+ message = dbus_message_new_signal (collection_path,
1997+ SECRET_COLLECTION_INTERFACE,
1998+ "ItemDeleted");
1999+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &item_path,
2000+ DBUS_TYPE_INVALID);
2001+
2002+ if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
2003+ message, NULL))
2004+ g_return_if_reached ();
2005+
2006+ dbus_message_unref (message);
2007+ g_free (collection_path);
2008+
2009+ gkd_secret_objects_emit_collection_changed (self, collection, "Items", NULL);
2010+}
2011
2012=== added file '.pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.h'
2013--- .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.h 1970-01-01 00:00:00 +0000
2014+++ .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.h 2013-03-14 13:26:21 +0000
2015@@ -0,0 +1,112 @@
2016+/*
2017+ * gnome-keyring
2018+ *
2019+ * Copyright (C) 2009 Stefan Walter
2020+ *
2021+ * This program is free software; you can redistribute it and/or modify
2022+ * it under the terms of the GNU Lesser General Public License as
2023+ * published by the Free Software Foundation; either version 2.1 of
2024+ * the License, or (at your option) any later version.
2025+ *
2026+ * This program is distributed in the hope that it will be useful, but
2027+ * WITHOUT ANY WARRANTY; without even the implied warranty of
2028+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2029+ * Lesser General Public License for more details.
2030+ *
2031+ * You should have received a copy of the GNU Lesser General Public
2032+ * License along with this program; if not, write to the Free Software
2033+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
2034+ * 02111-1307, USA.
2035+ */
2036+
2037+#ifndef __GKD_SECRET_OBJECTS_H__
2038+#define __GKD_SECRET_OBJECTS_H__
2039+
2040+#include "gkd-secret-types.h"
2041+
2042+#include <gck/gck.h>
2043+
2044+#include <glib-object.h>
2045+
2046+#include <dbus/dbus.h>
2047+
2048+#define GKD_SECRET_TYPE_OBJECTS (gkd_secret_objects_get_type ())
2049+#define GKD_SECRET_OBJECTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKD_SECRET_TYPE_OBJECTS, GkdSecretObjects))
2050+#define GKD_SECRET_OBJECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GKD_SECRET_TYPE_OBJECTS, GkdSecretObjectsClass))
2051+#define GKD_SECRET_IS_OBJECTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKD_SECRET_TYPE_OBJECTS))
2052+#define GKD_SECRET_IS_OBJECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GKD_SECRET_TYPE_OBJECTS))
2053+#define GKD_SECRET_OBJECTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKD_SECRET_TYPE_OBJECTS, GkdSecretObjectsClass))
2054+
2055+typedef struct _GkdSecretObjectsClass GkdSecretObjectsClass;
2056+
2057+struct _GkdSecretObjectsClass {
2058+ GObjectClass parent_class;
2059+};
2060+
2061+typedef void (*GkdSecretObjectsForeach) (GkdSecretObjects *self,
2062+ const gchar *path,
2063+ GckObject *object,
2064+ gpointer user_data);
2065+
2066+GType gkd_secret_objects_get_type (void);
2067+
2068+DBusMessage* gkd_secret_objects_dispatch (GkdSecretObjects *self,
2069+ DBusMessage *message);
2070+
2071+DBusMessage* gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
2072+ DBusMessage *message,
2073+ const gchar *base);
2074+
2075+DBusMessage* gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self,
2076+ DBusMessage *message);
2077+
2078+void gkd_secret_objects_foreach_collection (GkdSecretObjects *self,
2079+ DBusMessage *message,
2080+ GkdSecretObjectsForeach callback,
2081+ gpointer user_data);
2082+
2083+void gkd_secret_objects_foreach_item (GkdSecretObjects *self,
2084+ DBusMessage *message,
2085+ const gchar *base,
2086+ GkdSecretObjectsForeach callback,
2087+ gpointer user_data);
2088+
2089+void gkd_secret_objects_append_collection_paths (GkdSecretObjects *self,
2090+ DBusMessageIter *iter,
2091+ DBusMessage *message);
2092+
2093+void gkd_secret_objects_append_item_paths (GkdSecretObjects *self,
2094+ const gchar *base,
2095+ DBusMessageIter *iter,
2096+ DBusMessage *message);
2097+
2098+GckSlot* gkd_secret_objects_get_pkcs11_slot (GkdSecretObjects *self);
2099+
2100+GckObject* gkd_secret_objects_lookup_collection (GkdSecretObjects *self,
2101+ const gchar *caller,
2102+ const gchar *path);
2103+
2104+GckObject* gkd_secret_objects_lookup_item (GkdSecretObjects *self,
2105+ const gchar *caller,
2106+ const gchar *path);
2107+
2108+void gkd_secret_objects_emit_collection_locked (GkdSecretObjects *self,
2109+ GckObject *collection);
2110+
2111+void gkd_secret_objects_emit_collection_changed (GkdSecretObjects *self,
2112+ GckObject *collection,
2113+ ...) G_GNUC_NULL_TERMINATED;
2114+
2115+void gkd_secret_objects_emit_item_created (GkdSecretObjects *self,
2116+ GckObject *collection,
2117+ GckObject *item);
2118+
2119+void gkd_secret_objects_emit_item_changed (GkdSecretObjects *self,
2120+ GckObject *item,
2121+ ...) G_GNUC_NULL_TERMINATED;
2122+
2123+void gkd_secret_objects_emit_item_deleted (GkdSecretObjects *self,
2124+ GckObject *collection,
2125+ const gchar *item_path);
2126+
2127+#endif /* __GKD_SECRET_OBJECTS_H__ */
2128
2129=== added file '.pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-service.c'
2130--- .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-service.c 1970-01-01 00:00:00 +0000
2131+++ .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-service.c 2013-03-14 13:26:21 +0000
2132@@ -0,0 +1,1598 @@
2133+/*
2134+ * gnome-keyring
2135+ *
2136+ * Copyright (C) 2008 Stefan Walter
2137+ *
2138+ * This program is free software; you can redistribute it and/or modify
2139+ * it under the terms of the GNU Lesser General Public License as
2140+ * published by the Free Software Foundation; either version 2.1 of
2141+ * the License, or (at your option) any later version.
2142+ *
2143+ * This program is distributed in the hope that it will be useful, but
2144+ * WITHOUT ANY WARRANTY; without even the implied warranty of
2145+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2146+ * Lesser General Public License for more details.
2147+ *
2148+ * You should have received a copy of the GNU Lesser General Public
2149+ * License along with this program; if not, write to the Free Software
2150+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
2151+ * 02111-1307, USA.
2152+ */
2153+
2154+#include "config.h"
2155+
2156+#include "gkd-dbus-util.h"
2157+#include "gkd-secret-change.h"
2158+#include "gkd-secret-create.h"
2159+#include "gkd-secret-dispatch.h"
2160+#include "gkd-secret-error.h"
2161+#include "gkd-secret-introspect.h"
2162+#include "gkd-secret-lock.h"
2163+#include "gkd-secret-objects.h"
2164+#include "gkd-secret-prompt.h"
2165+#include "gkd-secret-property.h"
2166+#include "gkd-secret-secret.h"
2167+#include "gkd-secret-service.h"
2168+#include "gkd-secret-session.h"
2169+#include "gkd-secret-types.h"
2170+#include "gkd-secret-unlock.h"
2171+#include "gkd-secret-util.h"
2172+
2173+#include "egg/egg-error.h"
2174+#include "egg/egg-unix-credentials.h"
2175+
2176+#include <gck/gck.h>
2177+
2178+#include "pkcs11/pkcs11i.h"
2179+
2180+#include <string.h>
2181+
2182+enum {
2183+ PROP_0,
2184+ PROP_CONNECTION,
2185+ PROP_PKCS11_SLOT,
2186+};
2187+
2188+struct _GkdSecretService {
2189+ GObject parent;
2190+ DBusConnection *connection;
2191+ GHashTable *clients;
2192+ gchar *match_rule;
2193+ GkdSecretObjects *objects;
2194+ GHashTable *aliases;
2195+ GckSession *internal_session;
2196+ gchar *alias_directory;
2197+};
2198+
2199+typedef struct _ServiceClient {
2200+ gchar *caller_peer;
2201+ gchar *caller_exec;
2202+ pid_t caller_pid;
2203+ CK_G_APPLICATION app;
2204+ GckSession *pkcs11_session;
2205+ GHashTable *dispatch;
2206+} ServiceClient;
2207+
2208+/* Forward declaration */
2209+static void service_dispatch_message (GkdSecretService *, DBusMessage *);
2210+
2211+G_DEFINE_TYPE (GkdSecretService, gkd_secret_service, G_TYPE_OBJECT);
2212+
2213+/* -----------------------------------------------------------------------------
2214+ * INTERNAL
2215+ */
2216+
2217+static gchar*
2218+default_path (GkdSecretService *self)
2219+{
2220+ gchar *old_directory;
2221+ gchar *new_directory;
2222+
2223+ if (self->alias_directory == NULL) {
2224+ new_directory = g_build_filename (g_get_user_data_dir (), "keyrings", NULL);
2225+ old_directory = g_build_filename (g_get_home_dir (), ".gnome2", "keyrings", NULL);
2226+
2227+ if (!g_file_test (new_directory, G_FILE_TEST_IS_DIR) &&
2228+ g_file_test (old_directory, G_FILE_TEST_IS_DIR)) {
2229+ self->alias_directory = old_directory;
2230+ old_directory = NULL;
2231+ } else {
2232+ self->alias_directory = new_directory;
2233+ new_directory = NULL;
2234+ }
2235+
2236+ g_free (old_directory);
2237+ g_free (new_directory);
2238+ g_debug ("keyring alias directory: %s", self->alias_directory);
2239+ }
2240+
2241+ return g_build_filename (self->alias_directory, "default", NULL);
2242+}
2243+
2244+static void
2245+update_default (GkdSecretService *self, gboolean force)
2246+{
2247+ gchar *contents = NULL;
2248+ const gchar *identifier;
2249+ gchar *path;
2250+
2251+ if (!force) {
2252+ identifier = g_hash_table_lookup (self->aliases, "default");
2253+ if (identifier)
2254+ return;
2255+ }
2256+
2257+ path = default_path (self);
2258+ if (g_file_get_contents (path, &contents, NULL, NULL)) {
2259+ g_strstrip (contents);
2260+ if (!contents[0]) {
2261+ g_free (contents);
2262+ contents = NULL;
2263+ }
2264+ }
2265+ g_free (path);
2266+
2267+ g_hash_table_replace (self->aliases, g_strdup ("default"), contents);
2268+}
2269+
2270+static void
2271+store_default (GkdSecretService *self)
2272+{
2273+ GError *error = NULL;
2274+ const gchar *identifier;
2275+ gchar *path;
2276+
2277+ identifier = g_hash_table_lookup (self->aliases, "default");
2278+ if (!identifier)
2279+ return;
2280+
2281+ path = default_path (self);
2282+ if (!g_file_set_contents (path, identifier, -1, &error))
2283+ g_message ("couldn't store default keyring: %s", egg_error_message (error));
2284+ g_free (path);
2285+}
2286+
2287+static gboolean
2288+object_path_has_prefix (const gchar *path, const gchar *prefix)
2289+{
2290+ gsize len;
2291+
2292+ g_assert (prefix);
2293+
2294+ if (!path)
2295+ return FALSE;
2296+
2297+ len = strlen (prefix);
2298+ return g_ascii_strncasecmp (path, prefix, len) == 0 &&
2299+ (path[len] == '\0' || path[len] == '/');
2300+}
2301+
2302+static void
2303+dispose_and_unref (gpointer object)
2304+{
2305+ g_return_if_fail (G_IS_OBJECT (object));
2306+ g_object_run_dispose (G_OBJECT (object));
2307+ g_object_unref (object);
2308+}
2309+
2310+static void
2311+free_client (gpointer data)
2312+{
2313+ ServiceClient *client = data;
2314+
2315+ if (!client)
2316+ return;
2317+
2318+ /* Info about our client */
2319+ g_free (client->caller_peer);
2320+ g_free (client->caller_exec);
2321+
2322+ /* The session we use for accessing as our client */
2323+ if (client->pkcs11_session) {
2324+#if 0
2325+ gck_session_close (client->pkcs11_session, NULL);
2326+#endif
2327+ g_object_unref (client->pkcs11_session);
2328+ }
2329+
2330+ /* The sessions and prompts the client has open */
2331+ g_hash_table_destroy (client->dispatch);
2332+
2333+ g_free (client);
2334+}
2335+
2336+typedef struct _on_get_connection_unix_process_id_args {
2337+ GkdSecretService *self;
2338+ DBusMessage *message;
2339+} on_get_connection_unix_process_id_args;
2340+
2341+static void
2342+free_on_get_connection_unix_process_id_args (gpointer data)
2343+{
2344+ on_get_connection_unix_process_id_args *args = data;
2345+ if (args != NULL) {
2346+ g_object_unref (args->self);
2347+ dbus_message_unref (args->message);
2348+ g_free (args);
2349+ }
2350+}
2351+
2352+static void
2353+on_get_connection_unix_process_id (DBusPendingCall *pending, gpointer user_data)
2354+{
2355+ on_get_connection_unix_process_id_args *args = user_data;
2356+ DBusMessage *reply = NULL;
2357+ DBusError error = DBUS_ERROR_INIT;
2358+ dbus_uint32_t caller_pid = 0;
2359+ GkdSecretService *self;
2360+ ServiceClient *client;
2361+ const gchar *caller;
2362+
2363+ g_return_if_fail (GKD_SECRET_IS_SERVICE (args->self));
2364+ self = args->self;
2365+
2366+ /* Get the resulting process ID */
2367+ reply = dbus_pending_call_steal_reply (pending);
2368+ g_return_if_fail (reply);
2369+
2370+ caller = dbus_message_get_sender (args->message);
2371+ g_return_if_fail (caller);
2372+
2373+ client = g_hash_table_lookup (self->clients, caller);
2374+ if (client == NULL) {
2375+
2376+ /* An error returned from GetConnectionUnixProcessID */
2377+ if (dbus_set_error_from_message (&error, reply)) {
2378+ g_message ("couldn't get the caller's unix process id: %s", error.message);
2379+ caller_pid = 0;
2380+ dbus_error_free (&error);
2381+
2382+ /* A PID was returned from GetConnectionUnixProcessID */
2383+ } else {
2384+ if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &caller_pid, DBUS_TYPE_INVALID))
2385+ g_return_if_reached ();
2386+ }
2387+
2388+ /* Initialize the client object */
2389+ client = g_new0 (ServiceClient, 1);
2390+ client->caller_peer = g_strdup (caller);
2391+ client->caller_pid = caller_pid;
2392+ if (caller_pid != 0)
2393+ client->caller_exec = egg_unix_credentials_executable (caller_pid);
2394+ client->app.applicationData = client;
2395+ client->dispatch = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, dispose_and_unref);
2396+
2397+ g_hash_table_replace (self->clients, client->caller_peer, client);
2398+
2399+ /* Update default collection each time someone connects */
2400+ update_default (self, TRUE);
2401+ }
2402+
2403+ dbus_message_unref (reply);
2404+
2405+ /* Dispatch the original message again */
2406+ service_dispatch_message (self, args->message);
2407+}
2408+
2409+static void
2410+initialize_service_client (GkdSecretService *self, DBusMessage *message)
2411+{
2412+ on_get_connection_unix_process_id_args *args;
2413+ DBusMessage *request;
2414+ DBusPendingCall *pending;
2415+ const gchar *caller;
2416+
2417+ g_assert (GKD_SECRET_IS_SERVICE (self));
2418+ g_assert (message);
2419+
2420+ args = g_new0 (on_get_connection_unix_process_id_args, 1);
2421+ args->self = g_object_ref (self);
2422+ args->message = dbus_message_ref (message);
2423+
2424+ caller = dbus_message_get_sender (message);
2425+ g_return_if_fail (caller);
2426+
2427+ /* Message org.freedesktop.DBus.GetConnectionUnixProcessID(IN String caller) */
2428+ request = dbus_message_new_method_call ("org.freedesktop.DBus", "/org/freedesktop/DBus",
2429+ "org.freedesktop.DBus", "GetConnectionUnixProcessID");
2430+ if (!request || !dbus_message_append_args (request, DBUS_TYPE_STRING, &caller, DBUS_TYPE_INVALID))
2431+ g_return_if_reached ();
2432+
2433+ /*
2434+ * Send of request for GetConnectionUnixProcessID, with lowish timeout.
2435+ * We're only talking to the session bus, so the reply should be fast.
2436+ * In addition we want to send off a reply to our caller, before it
2437+ * times out.
2438+ */
2439+ if (!dbus_connection_send_with_reply (self->connection, request, &pending, 2000))
2440+ g_return_if_reached ();
2441+ dbus_message_unref (request);
2442+
2443+ /* Track our new session object, on this call */
2444+ dbus_pending_call_set_notify (pending, on_get_connection_unix_process_id, args,
2445+ free_on_get_connection_unix_process_id_args);
2446+ dbus_pending_call_unref (pending);
2447+}
2448+
2449+/* -----------------------------------------------------------------------------
2450+ * DBUS
2451+ */
2452+
2453+static DBusMessage*
2454+service_property_get (GkdSecretService *self, DBusMessage *message)
2455+{
2456+ DBusMessage *reply = NULL;
2457+ DBusMessageIter iter;
2458+ const gchar *interface;
2459+ const gchar *name;
2460+
2461+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface,
2462+ DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
2463+ return NULL;
2464+
2465+ if (!gkd_dbus_interface_match (SECRET_SERVICE_INTERFACE, interface))
2466+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
2467+ "Object does not have properties on interface '%s'",
2468+ interface);
2469+
2470+ /* The "Collections" property */
2471+ if (g_str_equal (name, "Collections")) {
2472+ reply = dbus_message_new_method_return (message);
2473+ dbus_message_iter_init_append (reply, &iter);
2474+ gkd_secret_objects_append_collection_paths (self->objects, &iter, message);
2475+
2476+ /* No such property */
2477+ } else {
2478+ reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
2479+ "Object does not have the '%s' property", name);
2480+ }
2481+
2482+ return reply;
2483+}
2484+
2485+static DBusMessage*
2486+service_property_set (GkdSecretService *self, DBusMessage *message)
2487+{
2488+ return NULL; /* TODO: Need to implement */
2489+}
2490+
2491+static void
2492+service_append_all_properties (GkdSecretService *self,
2493+ DBusMessageIter *iter)
2494+{
2495+ DBusMessageIter array;
2496+ DBusMessageIter dict;
2497+ const gchar *name;
2498+
2499+ dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{sv}", &array);
2500+
2501+ name = "Collections";
2502+ dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
2503+ dbus_message_iter_append_basic (&dict, DBUS_TYPE_STRING, &name);
2504+ gkd_secret_objects_append_collection_paths (self->objects, &dict, NULL);
2505+ dbus_message_iter_close_container (&array, &dict);
2506+
2507+ dbus_message_iter_close_container (iter, &array);
2508+}
2509+
2510+static DBusMessage*
2511+service_property_getall (GkdSecretService *self, DBusMessage *message)
2512+{
2513+ DBusMessage *reply = NULL;
2514+ DBusMessageIter iter;
2515+ const gchar *interface;
2516+
2517+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID))
2518+ return NULL;
2519+
2520+ if (!gkd_dbus_interface_match (SECRET_SERVICE_INTERFACE, interface))
2521+ return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
2522+ "Object does not have properties on interface '%s'",
2523+ interface);
2524+
2525+ reply = dbus_message_new_method_return (message);
2526+ dbus_message_iter_init_append (reply, &iter);
2527+ service_append_all_properties (self, &iter);
2528+ return reply;
2529+}
2530+
2531+static DBusMessage*
2532+service_method_open_session (GkdSecretService *self, DBusMessage *message)
2533+{
2534+ GkdSecretSession *session;
2535+ DBusMessage *reply = NULL;
2536+ const gchar *caller;
2537+
2538+ if (!dbus_message_has_signature (message, "sv"))
2539+ return NULL;
2540+
2541+ caller = dbus_message_get_sender (message);
2542+
2543+ /* Now we can create a session with this information */
2544+ session = gkd_secret_session_new (self, caller);
2545+ reply = gkd_secret_session_handle_open (session, message);
2546+
2547+ if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
2548+ gkd_secret_service_publish_dispatch (self, caller,
2549+ GKD_SECRET_DISPATCH (session));
2550+
2551+ g_object_unref (session);
2552+ return reply;
2553+}
2554+
2555+static DBusMessage*
2556+service_method_create_collection (GkdSecretService *self, DBusMessage *message)
2557+{
2558+ GckBuilder builder = GCK_BUILDER_INIT;
2559+ DBusMessageIter iter, array;
2560+ GckAttributes *attrs;
2561+ GkdSecretCreate *create;
2562+ DBusMessage *reply;
2563+ const gchar *path;
2564+ const gchar *alias;
2565+ const char *caller;
2566+ const gchar *coll;
2567+
2568+ /* Parse the incoming message */
2569+ if (!dbus_message_has_signature (message, "a{sv}s"))
2570+ return NULL;
2571+ if (!dbus_message_iter_init (message, &iter))
2572+ g_return_val_if_reached (NULL);
2573+ dbus_message_iter_recurse (&iter, &array);
2574+ if (!gkd_secret_property_parse_all (&array, SECRET_COLLECTION_INTERFACE, &builder)) {
2575+ gck_builder_clear (&builder);
2576+ return dbus_message_new_error_printf (message, DBUS_ERROR_INVALID_ARGS,
2577+ "Invalid properties");
2578+ }
2579+ if (!dbus_message_iter_next (&iter))
2580+ g_return_val_if_reached (NULL);
2581+ dbus_message_iter_get_basic (&iter, &alias);
2582+
2583+ /* Empty alias is no alias */
2584+ if (alias) {
2585+ if (!alias[0]) {
2586+ alias = NULL;
2587+ } else if (!g_str_equal (alias, "default")) {
2588+ gck_builder_clear (&builder);
2589+ return dbus_message_new_error (message, DBUS_ERROR_NOT_SUPPORTED,
2590+ "Only the 'default' alias is supported");
2591+ }
2592+ }
2593+
2594+ gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
2595+ attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
2596+
2597+ /* Create the prompt object, for the password */
2598+ caller = dbus_message_get_sender (message);
2599+ create = gkd_secret_create_new (self, caller, attrs, alias);
2600+ gck_attributes_unref (attrs);
2601+
2602+ path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (create));
2603+ gkd_secret_service_publish_dispatch (self, caller,
2604+ GKD_SECRET_DISPATCH (create));
2605+
2606+ coll = "/";
2607+ reply = dbus_message_new_method_return (message);
2608+ dbus_message_append_args (reply,
2609+ DBUS_TYPE_OBJECT_PATH, &coll,
2610+ DBUS_TYPE_OBJECT_PATH, &path,
2611+ DBUS_TYPE_INVALID);
2612+
2613+ g_object_unref (create);
2614+ return reply;
2615+}
2616+
2617+static DBusMessage*
2618+service_method_lock_service (GkdSecretService *self, DBusMessage *message)
2619+{
2620+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INVALID))
2621+ return NULL;
2622+
2623+ /* TODO: Need to implement */
2624+ return dbus_message_new_method_return (message);
2625+}
2626+
2627+static DBusMessage*
2628+service_method_unlock (GkdSecretService *self, DBusMessage *message)
2629+{
2630+ GkdSecretUnlock *unlock;
2631+ DBusMessage *reply;
2632+ const char *caller;
2633+ const gchar *path;
2634+ int n_objpaths, i;
2635+ char **objpaths;
2636+
2637+ if (!dbus_message_get_args (message, NULL,
2638+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &objpaths, &n_objpaths,
2639+ DBUS_TYPE_INVALID))
2640+ return NULL;
2641+
2642+ caller = dbus_message_get_sender (message);
2643+ unlock = gkd_secret_unlock_new (self, caller, NULL);
2644+ for (i = 0; i < n_objpaths; ++i)
2645+ gkd_secret_unlock_queue (unlock, objpaths[i]);
2646+ dbus_free_string_array (objpaths);
2647+
2648+ /* So do we need to prompt? */
2649+ if (gkd_secret_unlock_have_queued (unlock)) {
2650+ gkd_secret_service_publish_dispatch (self, caller,
2651+ GKD_SECRET_DISPATCH (unlock));
2652+ path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (unlock));
2653+
2654+ /* No need to prompt */
2655+ } else {
2656+ path = "/";
2657+ }
2658+
2659+ reply = dbus_message_new_method_return (message);
2660+ objpaths = gkd_secret_unlock_get_results (unlock, &n_objpaths);
2661+ dbus_message_append_args (reply,
2662+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &objpaths, n_objpaths,
2663+ DBUS_TYPE_OBJECT_PATH, &path,
2664+ DBUS_TYPE_INVALID);
2665+
2666+ gkd_secret_unlock_reset_results (unlock);
2667+ g_object_unref (unlock);
2668+
2669+ return reply;
2670+}
2671+
2672+static DBusMessage*
2673+service_method_lock (GkdSecretService *self, DBusMessage *message)
2674+{
2675+ DBusMessage *reply;
2676+ const char *caller;
2677+ const gchar *prompt;
2678+ GckObject *collection;
2679+ int n_objpaths, i;
2680+ char **objpaths;
2681+ GPtrArray *array;
2682+
2683+ if (!dbus_message_get_args (message, NULL,
2684+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &objpaths, &n_objpaths,
2685+ DBUS_TYPE_INVALID))
2686+ return NULL;
2687+
2688+ caller = dbus_message_get_sender (message);
2689+ array = g_ptr_array_new ();
2690+ for (i = 0; i < n_objpaths; ++i) {
2691+ collection = gkd_secret_objects_lookup_collection (self->objects, caller, objpaths[i]);
2692+ if (collection != NULL) {
2693+ if (gkd_secret_lock (collection, NULL)) {
2694+ g_ptr_array_add (array, objpaths[i]);
2695+ gkd_secret_objects_emit_collection_locked (self->objects,
2696+ collection);
2697+ }
2698+ g_object_unref (collection);
2699+ }
2700+ }
2701+
2702+ prompt = "/";
2703+ reply = dbus_message_new_method_return (message);
2704+ dbus_message_append_args (reply,
2705+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &array->pdata, array->len,
2706+ DBUS_TYPE_OBJECT_PATH, &prompt,
2707+ DBUS_TYPE_INVALID);
2708+
2709+ dbus_free_string_array (objpaths);
2710+ return reply;
2711+}
2712+
2713+static DBusMessage*
2714+service_method_change_lock (GkdSecretService *self, DBusMessage *message)
2715+{
2716+ GkdSecretChange *change;
2717+ DBusMessage *reply;
2718+ const char *caller;
2719+ const gchar *path;
2720+ GckObject *collection;
2721+
2722+ caller = dbus_message_get_sender (message);
2723+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
2724+ return NULL;
2725+
2726+ /* Make sure it exists */
2727+ collection = gkd_secret_objects_lookup_collection (self->objects, caller, path);
2728+ if (!collection)
2729+ return dbus_message_new_error (message, SECRET_ERROR_NO_SUCH_OBJECT,
2730+ "The collection does not exist");
2731+ g_object_unref (collection);
2732+
2733+ change = gkd_secret_change_new (self, caller, path);
2734+ path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (change));
2735+ gkd_secret_service_publish_dispatch (self, caller,
2736+ GKD_SECRET_DISPATCH (change));
2737+
2738+ reply = dbus_message_new_method_return (message);
2739+ dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
2740+
2741+ g_object_unref (change);
2742+ return reply;
2743+}
2744+
2745+static DBusMessage*
2746+service_method_read_alias (GkdSecretService *self, DBusMessage *message)
2747+{
2748+ DBusMessage *reply;
2749+ const char *alias;
2750+ gchar *path = NULL;
2751+ const gchar *identifier;
2752+ GckObject *collection = NULL;
2753+
2754+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &alias, DBUS_TYPE_INVALID))
2755+ return NULL;
2756+
2757+ identifier = gkd_secret_service_get_alias (self, alias);
2758+ if (identifier)
2759+ path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, -1);
2760+
2761+ /* Make sure it actually exists */
2762+ if (path)
2763+ collection = gkd_secret_objects_lookup_collection (self->objects,
2764+ dbus_message_get_sender (message), path);
2765+ if (collection == NULL) {
2766+ g_free (path);
2767+ path = NULL;
2768+ } else {
2769+ g_object_unref (collection);
2770+ }
2771+
2772+ reply = dbus_message_new_method_return (message);
2773+ if (path == NULL)
2774+ path = g_strdup ("/");
2775+ dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
2776+ g_free (path);
2777+
2778+ return reply;
2779+}
2780+
2781+static DBusMessage*
2782+service_method_set_alias (GkdSecretService *self, DBusMessage *message)
2783+{
2784+ GckObject *collection;
2785+ gchar *identifier;
2786+ const char *alias;
2787+ const char *path;
2788+
2789+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &alias,
2790+ DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
2791+ return NULL;
2792+
2793+ g_return_val_if_fail (alias, NULL);
2794+ g_return_val_if_fail (path, NULL);
2795+
2796+ if (!g_str_equal (alias, "default"))
2797+ return dbus_message_new_error (message, DBUS_ERROR_NOT_SUPPORTED,
2798+ "Only the 'default' alias is supported");
2799+
2800+ /* No default collection */
2801+ if (g_str_equal (path, "/")) {
2802+ identifier = g_strdup ("");
2803+
2804+ /* Find a collection with that path */
2805+ } else {
2806+ if (!object_path_has_prefix (path, SECRET_COLLECTION_PREFIX) ||
2807+ !gkd_secret_util_parse_path (path, &identifier, NULL))
2808+ return dbus_message_new_error (message, DBUS_ERROR_INVALID_ARGS,
2809+ "Invalid collection object path");
2810+
2811+ collection = gkd_secret_objects_lookup_collection (self->objects,
2812+ dbus_message_get_sender (message), path);
2813+ if (collection == NULL) {
2814+ g_free (identifier);
2815+ return dbus_message_new_error (message, SECRET_ERROR_NO_SUCH_OBJECT,
2816+ "No such collection exists");
2817+ }
2818+
2819+ g_object_unref (collection);
2820+ }
2821+
2822+ gkd_secret_service_set_alias (self, alias, identifier);
2823+ g_free (identifier);
2824+
2825+ return dbus_message_new_method_return (message);
2826+}
2827+
2828+static DBusMessage*
2829+service_method_create_with_master_password (GkdSecretService *self, DBusMessage *message)
2830+{
2831+ GckBuilder builder = GCK_BUILDER_INIT;
2832+ DBusError derr = DBUS_ERROR_INIT;
2833+ DBusMessageIter iter, array;
2834+ DBusMessage *reply = NULL;
2835+ GkdSecretSecret *secret = NULL;
2836+ GckAttributes *attrs = NULL;
2837+ GError *error = NULL;
2838+ gchar *path;
2839+
2840+ /* Parse the incoming message */
2841+ if (!dbus_message_has_signature (message, "a{sv}(oayays)"))
2842+ return NULL;
2843+ if (!dbus_message_iter_init (message, &iter))
2844+ g_return_val_if_reached (NULL);
2845+ dbus_message_iter_recurse (&iter, &array);
2846+ if (!gkd_secret_property_parse_all (&array, SECRET_COLLECTION_INTERFACE, &builder)) {
2847+ gck_builder_clear (&builder);
2848+ return dbus_message_new_error (message, DBUS_ERROR_INVALID_ARGS,
2849+ "Invalid properties argument");
2850+ }
2851+ dbus_message_iter_next (&iter);
2852+ secret = gkd_secret_secret_parse (self, message, &iter, &derr);
2853+ if (secret == NULL) {
2854+ gck_builder_clear (&builder);
2855+ return gkd_secret_error_to_reply (message, &derr);
2856+ }
2857+
2858+ gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
2859+ attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
2860+ path = gkd_secret_create_with_secret (attrs, secret, &error);
2861+ gck_attributes_unref (attrs);
2862+ gkd_secret_secret_free (secret);
2863+
2864+ if (path == NULL)
2865+ return gkd_secret_propagate_error (message, "Couldn't create collection", error);
2866+
2867+ /* Notify the callers that a collection was created */
2868+ gkd_secret_service_emit_collection_created (self, path);
2869+
2870+ reply = dbus_message_new_method_return (message);
2871+ dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
2872+ g_free (path);
2873+
2874+ return reply;
2875+}
2876+
2877+static DBusMessage*
2878+service_method_change_with_master_password (GkdSecretService *self, DBusMessage *message)
2879+{
2880+ DBusError derr = DBUS_ERROR_INIT;
2881+ GkdSecretSecret *original, *master;
2882+ GckObject *collection;
2883+ DBusMessageIter iter;
2884+ DBusMessage *reply;
2885+ GError *error = NULL;
2886+ const gchar *path;
2887+
2888+ /* Parse the incoming message */
2889+ if (!dbus_message_has_signature (message, "o(oayays)(oayays)"))
2890+ return NULL;
2891+ if (!dbus_message_iter_init (message, &iter))
2892+ g_return_val_if_reached (NULL);
2893+ dbus_message_iter_get_basic (&iter, &path);
2894+ dbus_message_iter_next (&iter);
2895+ original = gkd_secret_secret_parse (self, message, &iter, &derr);
2896+ if (original == NULL)
2897+ return gkd_secret_error_to_reply (message, &derr);
2898+ dbus_message_iter_next (&iter);
2899+ master = gkd_secret_secret_parse (self, message, &iter, &derr);
2900+ if (master == NULL) {
2901+ gkd_secret_secret_free (original);
2902+ return gkd_secret_error_to_reply (message, &derr);
2903+ }
2904+
2905+ /* Make sure we have such a collection */
2906+ collection = gkd_secret_objects_lookup_collection (self->objects,
2907+ dbus_message_get_sender (message),
2908+ path);
2909+
2910+ /* No such collection */
2911+ if (collection == NULL)
2912+ reply = dbus_message_new_error (message, SECRET_ERROR_NO_SUCH_OBJECT,
2913+ "The collection does not exist");
2914+
2915+ /* Success */
2916+ else if (gkd_secret_change_with_secrets (collection, NULL, original, master, &error))
2917+ reply = dbus_message_new_method_return (message);
2918+
2919+ /* Failure */
2920+ else
2921+ reply = gkd_secret_propagate_error (message, "Couldn't change collection password", error);
2922+
2923+ gkd_secret_secret_free (original);
2924+ gkd_secret_secret_free (master);
2925+
2926+ if (collection)
2927+ g_object_unref (collection);
2928+
2929+ return reply;
2930+}
2931+
2932+static DBusMessage*
2933+service_method_unlock_with_master_password (GkdSecretService *self, DBusMessage *message)
2934+{
2935+ DBusError derr = DBUS_ERROR_INIT;
2936+ GkdSecretSecret *master;
2937+ GError *error = NULL;
2938+ GckObject *collection;
2939+ DBusMessageIter iter;
2940+ DBusMessage *reply;
2941+ const gchar *path;
2942+
2943+ /* Parse the incoming message */
2944+ if (!dbus_message_has_signature (message, "o(oayays)"))
2945+ return NULL;
2946+ if (!dbus_message_iter_init (message, &iter))
2947+ g_return_val_if_reached (NULL);
2948+ dbus_message_iter_get_basic (&iter, &path);
2949+ dbus_message_iter_next (&iter);
2950+ master = gkd_secret_secret_parse (self, message, &iter, &derr);
2951+ if (master == NULL)
2952+ return gkd_secret_error_to_reply (message, &derr);
2953+
2954+ /* Make sure we have such a collection */
2955+ collection = gkd_secret_objects_lookup_collection (self->objects,
2956+ dbus_message_get_sender (message),
2957+ path);
2958+
2959+ /* No such collection */
2960+ if (collection == NULL) {
2961+ reply = dbus_message_new_error (message, SECRET_ERROR_NO_SUCH_OBJECT,
2962+ "The collection does not exist");
2963+
2964+ /* Success */
2965+ } else if (gkd_secret_unlock_with_secret (collection, master, &error)) {
2966+ reply = dbus_message_new_method_return (message);
2967+ gkd_secret_objects_emit_collection_locked (self->objects, collection);
2968+
2969+ /* Failure */
2970+ } else {
2971+ reply = gkd_secret_propagate_error (message, "Couldn't unlock collection", error);
2972+ }
2973+
2974+ gkd_secret_secret_free (master);
2975+
2976+ if (collection)
2977+ g_object_unref (collection);
2978+
2979+ return reply;
2980+}
2981+
2982+static void
2983+on_each_path_append_to_array (GkdSecretObjects *self,
2984+ const gchar *path,
2985+ GckObject *object,
2986+ gpointer user_data)
2987+{
2988+ GPtrArray *array = user_data;
2989+ g_ptr_array_add (array, g_strdup (path));
2990+}
2991+
2992+static DBusMessage *
2993+service_introspect (GkdSecretService *self,
2994+ DBusMessage *message)
2995+{
2996+ GPtrArray *names;
2997+ DBusMessage *reply;
2998+ ServiceClient *client;
2999+ const gchar *caller;
3000+ const gchar *path;
3001+ GHashTableIter iter;
3002+
3003+ names = g_ptr_array_new_with_free_func (g_free);
3004+ gkd_secret_objects_foreach_collection (self->objects, message,
3005+ on_each_path_append_to_array,
3006+ names);
3007+
3008+ /* Lookup all sessions and prompts for this client */
3009+ caller = dbus_message_get_sender (message);
3010+ if (caller != NULL) {
3011+ client = g_hash_table_lookup (self->clients, caller);
3012+ if (client != NULL) {
3013+ g_hash_table_iter_init (&iter, client->dispatch);
3014+ while (g_hash_table_iter_next (&iter, (gpointer *)&path, NULL))
3015+ g_ptr_array_add (names, g_strdup (path));
3016+ }
3017+ }
3018+
3019+ g_ptr_array_add (names, NULL);
3020+
3021+ reply = gkd_dbus_introspect_handle (message, gkd_secret_introspect_service,
3022+ (const gchar **)names->pdata);
3023+
3024+ g_ptr_array_unref (names);
3025+ return reply;
3026+}
3027+
3028+static DBusMessage*
3029+service_message_handler (GkdSecretService *self, DBusMessage *message)
3030+{
3031+ g_return_val_if_fail (message, NULL);
3032+ g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
3033+
3034+ /* org.freedesktop.Secret.Service.OpenSession() */
3035+ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "OpenSession"))
3036+ return service_method_open_session (self, message);
3037+
3038+ /* org.freedesktop.Secret.Service.CreateCollection() */
3039+ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "CreateCollection"))
3040+ return service_method_create_collection (self, message);
3041+
3042+ /* org.freedesktop.Secret.Service.LockService() */
3043+ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "LockService"))
3044+ return service_method_lock_service (self, message);
3045+
3046+ /* org.freedesktop.Secret.Service.SearchItems() */
3047+ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "SearchItems"))
3048+ return gkd_secret_objects_handle_search_items (self->objects, message, NULL);
3049+
3050+ /* org.freedesktop.Secret.Service.GetSecrets() */
3051+ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "GetSecrets"))
3052+ return gkd_secret_objects_handle_get_secrets (self->objects, message);
3053+
3054+ /* org.freedesktop.Secret.Service.Unlock() */
3055+ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "Unlock"))
3056+ return service_method_unlock (self, message);
3057+
3058+ /* org.freedesktop.Secret.Service.Lock() */
3059+ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "Lock"))
3060+ return service_method_lock (self, message);
3061+
3062+ /* org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface.ChangeWithPrompt() */
3063+ if (dbus_message_is_method_call (message, INTERNAL_SERVICE_INTERFACE, "ChangeWithPrompt") ||
3064+ dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "ChangeLock"))
3065+ return service_method_change_lock (self, message);
3066+
3067+ /* org.freedesktop.Secret.Service.ReadAlias() */
3068+ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "ReadAlias"))
3069+ return service_method_read_alias (self, message);
3070+
3071+ /* org.freedesktop.Secret.Service.SetAlias() */
3072+ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "SetAlias"))
3073+ return service_method_set_alias (self, message);
3074+
3075+ /* org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface.CreateWithMasterPassword */
3076+ if (dbus_message_is_method_call (message, INTERNAL_SERVICE_INTERFACE, "CreateWithMasterPassword"))
3077+ return service_method_create_with_master_password (self, message);
3078+
3079+ /* org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface.ChangeWithMasterPassword() */
3080+ if (dbus_message_is_method_call (message, INTERNAL_SERVICE_INTERFACE, "ChangeWithMasterPassword"))
3081+ return service_method_change_with_master_password (self, message);
3082+
3083+ /* org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface.UnlockWithMasterPassword() */
3084+ if (dbus_message_is_method_call (message, INTERNAL_SERVICE_INTERFACE, "UnlockWithMasterPassword"))
3085+ return service_method_unlock_with_master_password (self, message);
3086+
3087+ /* org.freedesktop.DBus.Properties.Get() */
3088+ if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Get"))
3089+ return service_property_get (self, message);
3090+
3091+ /* org.freedesktop.DBus.Properties.Set() */
3092+ else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Set"))
3093+ return service_property_set (self, message);
3094+
3095+ /* org.freedesktop.DBus.Properties.GetAll() */
3096+ else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "GetAll"))
3097+ return service_property_getall (self, message);
3098+
3099+ /* org.freedesktop.DBus.Introspectable.Introspect() */
3100+ else if (dbus_message_has_interface (message, DBUS_INTERFACE_INTROSPECTABLE))
3101+ return service_introspect (self, message);
3102+
3103+ return NULL;
3104+}
3105+
3106+static gboolean
3107+root_dispatch_message (GkdSecretService *self,
3108+ DBusMessage *message)
3109+{
3110+ DBusMessage *reply = NULL;
3111+
3112+ if (dbus_message_has_interface (message, DBUS_INTERFACE_INTROSPECTABLE))
3113+ reply = gkd_dbus_introspect_handle (message, gkd_secret_introspect_root, NULL);
3114+
3115+ if (reply != NULL) {
3116+ dbus_connection_send (self->connection, reply, NULL);
3117+ dbus_message_unref (reply);
3118+ return TRUE;
3119+ }
3120+
3121+ return FALSE;
3122+}
3123+
3124+static void
3125+service_dispatch_message (GkdSecretService *self, DBusMessage *message)
3126+{
3127+ DBusMessage *reply = NULL;
3128+ const gchar *caller;
3129+ ServiceClient *client;
3130+ const gchar *path;
3131+ gpointer object;
3132+
3133+ g_assert (GKD_SECRET_IS_SERVICE (self));
3134+ g_assert (message);
3135+
3136+ /* The first thing we do is try to allocate a client context */
3137+ caller = dbus_message_get_sender (message);
3138+ if (caller == NULL) {
3139+ reply = dbus_message_new_error (message, DBUS_ERROR_FAILED,
3140+ "Could not not identify calling client application");
3141+ dbus_connection_send (self->connection, reply, NULL);
3142+ dbus_message_unref (reply);
3143+ return;
3144+ }
3145+
3146+ client = g_hash_table_lookup (self->clients, caller);
3147+ if (client == NULL) {
3148+ initialize_service_client (self, message);
3149+ return; /* This function called again, when client is initialized */
3150+ }
3151+
3152+ path = dbus_message_get_path (message);
3153+ g_return_if_fail (path);
3154+
3155+ /* Dispatched to a session or prompt */
3156+ if (object_path_has_prefix (path, SECRET_SESSION_PREFIX) ||
3157+ object_path_has_prefix (path, SECRET_PROMPT_PREFIX)) {
3158+ object = g_hash_table_lookup (client->dispatch, path);
3159+ if (object == NULL)
3160+ reply = gkd_secret_error_no_such_object (message);
3161+ else
3162+ reply = gkd_secret_dispatch_message (GKD_SECRET_DISPATCH (object), message);
3163+
3164+ /* Dispatched to a collection, off it goes */
3165+ } else if (object_path_has_prefix (path, SECRET_COLLECTION_PREFIX) ||
3166+ object_path_has_prefix (path, SECRET_ALIAS_PREFIX)) {
3167+ reply = gkd_secret_objects_dispatch (self->objects, message);
3168+
3169+ /* Addressed to the service */
3170+ } else if (g_str_equal (path, SECRET_SERVICE_PATH)) {
3171+ reply = service_message_handler (self, message);
3172+ }
3173+
3174+ /* Should we send an error? */
3175+ if (!reply && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL) {
3176+ if (!dbus_message_get_no_reply (message)) {
3177+ reply = dbus_message_new_error_printf (message, DBUS_ERROR_UNKNOWN_METHOD,
3178+ "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist\n",
3179+ dbus_message_get_member (message),
3180+ dbus_message_get_signature (message),
3181+ dbus_message_get_interface (message));
3182+ }
3183+ }
3184+
3185+ if (reply) {
3186+ dbus_connection_send (self->connection, reply, NULL);
3187+ dbus_message_unref (reply);
3188+ }
3189+}
3190+
3191+static DBusHandlerResult
3192+gkd_secret_service_filter_handler (DBusConnection *conn, DBusMessage *message, gpointer user_data)
3193+{
3194+ GkdSecretService *self = user_data;
3195+ const gchar *object_name;
3196+ const gchar *old_owner;
3197+ const gchar *new_owner;
3198+ const gchar *path;
3199+ const gchar *interface;
3200+
3201+ g_return_val_if_fail (conn && message, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
3202+ g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
3203+
3204+ /* org.freedesktop.DBus.NameOwnerChanged(STRING name, STRING old_owner, STRING new_owner) */
3205+ if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged") &&
3206+ dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &object_name,
3207+ DBUS_TYPE_STRING, &old_owner, DBUS_TYPE_STRING, &new_owner,
3208+ DBUS_TYPE_INVALID)) {
3209+
3210+ /*
3211+ * A peer is connecting or disconnecting from the bus,
3212+ * remove any client info, when client gone.
3213+ */
3214+
3215+ g_return_val_if_fail (object_name && new_owner, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
3216+ if (g_str_equal (new_owner, "") && object_name[0] == ':')
3217+ g_hash_table_remove (self->clients, object_name);
3218+
3219+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3220+ }
3221+
3222+ /*
3223+ * If the path is a within our object tree, then we do our own dispatch.
3224+ */
3225+ path = dbus_message_get_path (message);
3226+ switch (dbus_message_get_type (message)) {
3227+
3228+ /* Dispatch any method call on our interfaces, for our objects */
3229+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
3230+ if (path != NULL && g_str_equal (path, "/")) {
3231+ if (root_dispatch_message (self, message))
3232+ return DBUS_HANDLER_RESULT_HANDLED;
3233+ }
3234+
3235+ if (object_path_has_prefix (path, SECRET_SERVICE_PATH)) {
3236+ interface = dbus_message_get_interface (message);
3237+ if (interface == NULL ||
3238+ g_str_has_prefix (interface, SECRET_INTERFACE_PREFIX) ||
3239+ g_str_equal (interface, DBUS_INTERFACE_PROPERTIES) ||
3240+ g_str_equal (interface, INTERNAL_SERVICE_INTERFACE) ||
3241+ g_str_equal (interface, DBUS_INTERFACE_INTROSPECTABLE)) {
3242+ service_dispatch_message (self, message);
3243+ return DBUS_HANDLER_RESULT_HANDLED;
3244+ }
3245+ }
3246+ break;
3247+
3248+ /* Dispatch any signal for one of our objects */
3249+ case DBUS_MESSAGE_TYPE_SIGNAL:
3250+ if (object_path_has_prefix (path, SECRET_SERVICE_PATH)) {
3251+ service_dispatch_message (self, message);
3252+ return DBUS_HANDLER_RESULT_HANDLED;
3253+ }
3254+ break;
3255+
3256+ default:
3257+ break;
3258+ }
3259+
3260+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3261+}
3262+
3263+/* -----------------------------------------------------------------------------
3264+ * OBJECT
3265+ */
3266+
3267+static GObject*
3268+gkd_secret_service_constructor (GType type, guint n_props, GObjectConstructParam *props)
3269+{
3270+ GkdSecretService *self = GKD_SECRET_SERVICE (G_OBJECT_CLASS (gkd_secret_service_parent_class)->constructor(type, n_props, props));
3271+ DBusError error = DBUS_ERROR_INIT;
3272+ GckSlot *slot = NULL;
3273+ guint i;
3274+
3275+ g_return_val_if_fail (self, NULL);
3276+ g_return_val_if_fail (self->connection, NULL);
3277+
3278+ /* Find the pkcs11-slot parameter */
3279+ for (i = 0; !slot && i < n_props; ++i) {
3280+ if (g_str_equal (props[i].pspec->name, "pkcs11-slot"))
3281+ slot = g_value_get_object (props[i].value);
3282+ }
3283+
3284+ /* Create our objects proxy */
3285+ g_return_val_if_fail (GCK_IS_SLOT (slot), NULL);
3286+ self->objects = g_object_new (GKD_SECRET_TYPE_OBJECTS,
3287+ "pkcs11-slot", slot, "service", self, NULL);
3288+
3289+ /* Register for signals that let us know when clients leave the bus */
3290+ self->match_rule = g_strdup_printf ("type='signal',member=NameOwnerChanged,"
3291+ "interface='" DBUS_INTERFACE_DBUS "'");
3292+ dbus_bus_add_match (self->connection, self->match_rule, &error);
3293+ if (dbus_error_is_set (&error)) {
3294+ g_warning ("couldn't listen for NameOwnerChanged signal on session bus: %s", error.message);
3295+ dbus_error_free (&error);
3296+ g_free (self->match_rule);
3297+ self->match_rule = NULL;
3298+ }
3299+
3300+ if (!dbus_connection_add_filter (self->connection, gkd_secret_service_filter_handler, self, NULL))
3301+ g_return_val_if_reached (NULL);
3302+
3303+ return G_OBJECT (self);
3304+}
3305+
3306+static void
3307+gkd_secret_service_init (GkdSecretService *self)
3308+{
3309+ self->clients = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_client);
3310+ self->aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
3311+}
3312+
3313+static void
3314+gkd_secret_service_dispose (GObject *obj)
3315+{
3316+ GkdSecretService *self = GKD_SECRET_SERVICE (obj);
3317+
3318+ if (self->match_rule) {
3319+ g_return_if_fail (self->connection);
3320+ dbus_bus_remove_match (self->connection, self->match_rule, NULL);
3321+ g_free (self->match_rule);
3322+ self->match_rule = NULL;
3323+ }
3324+
3325+ /* Closes all the clients */
3326+ g_hash_table_remove_all (self->clients);
3327+
3328+ /* Hide all the objects */
3329+ if (self->objects) {
3330+ g_object_run_dispose (G_OBJECT (self->objects));
3331+ g_object_unref (self->objects);
3332+ self->objects = NULL;
3333+ }
3334+
3335+ if (self->connection) {
3336+ dbus_connection_remove_filter (self->connection, gkd_secret_service_filter_handler, self);
3337+ dbus_connection_unref (self->connection);
3338+ self->connection = NULL;
3339+ }
3340+
3341+ if (self->internal_session) {
3342+ dispose_and_unref (self->internal_session);
3343+ self->internal_session = NULL;
3344+ }
3345+
3346+ G_OBJECT_CLASS (gkd_secret_service_parent_class)->dispose (obj);
3347+}
3348+
3349+static void
3350+gkd_secret_service_finalize (GObject *obj)
3351+{
3352+ GkdSecretService *self = GKD_SECRET_SERVICE (obj);
3353+
3354+ g_assert (g_hash_table_size (self->clients) == 0);
3355+ g_hash_table_destroy (self->clients);
3356+ self->clients = NULL;
3357+
3358+ g_hash_table_destroy (self->aliases);
3359+ self->aliases = NULL;
3360+
3361+ G_OBJECT_CLASS (gkd_secret_service_parent_class)->finalize (obj);
3362+}
3363+
3364+static void
3365+gkd_secret_service_set_property (GObject *obj, guint prop_id, const GValue *value,
3366+ GParamSpec *pspec)
3367+{
3368+ GkdSecretService *self = GKD_SECRET_SERVICE (obj);
3369+
3370+ switch (prop_id) {
3371+ case PROP_CONNECTION:
3372+ g_return_if_fail (!self->connection);
3373+ self->connection = g_value_dup_boxed (value);
3374+ g_return_if_fail (self->connection);
3375+ break;
3376+ case PROP_PKCS11_SLOT:
3377+ g_return_if_fail (!self->objects);
3378+ break;
3379+ default:
3380+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
3381+ break;
3382+ }
3383+}
3384+
3385+static void
3386+gkd_secret_service_get_property (GObject *obj, guint prop_id, GValue *value,
3387+ GParamSpec *pspec)
3388+{
3389+ GkdSecretService *self = GKD_SECRET_SERVICE (obj);
3390+
3391+ switch (prop_id) {
3392+ case PROP_CONNECTION:
3393+ g_value_set_boxed (value, gkd_secret_service_get_connection (self));
3394+ break;
3395+ case PROP_PKCS11_SLOT:
3396+ g_value_set_object (value, gkd_secret_service_get_pkcs11_slot (self));
3397+ break;
3398+ default:
3399+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
3400+ break;
3401+ }
3402+}
3403+
3404+static void
3405+gkd_secret_service_class_init (GkdSecretServiceClass *klass)
3406+{
3407+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3408+
3409+ gobject_class->constructor = gkd_secret_service_constructor;
3410+ gobject_class->dispose = gkd_secret_service_dispose;
3411+ gobject_class->finalize = gkd_secret_service_finalize;
3412+ gobject_class->set_property = gkd_secret_service_set_property;
3413+ gobject_class->get_property = gkd_secret_service_get_property;
3414+
3415+ g_object_class_install_property (gobject_class, PROP_CONNECTION,
3416+ g_param_spec_boxed ("connection", "Connection", "DBus Connection",
3417+ GKD_DBUS_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
3418+
3419+ g_object_class_install_property (gobject_class, PROP_PKCS11_SLOT,
3420+ g_param_spec_object ("pkcs11-slot", "Pkcs11 Slot", "PKCS#11 slot that we use for secrets",
3421+ GCK_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
3422+}
3423+
3424+/* -----------------------------------------------------------------------------
3425+ * PUBLIC
3426+ */
3427+
3428+void
3429+gkd_secret_service_send (GkdSecretService *self, DBusMessage *message)
3430+{
3431+ g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
3432+ dbus_connection_send (self->connection, message, NULL);
3433+}
3434+
3435+GkdSecretObjects*
3436+gkd_secret_service_get_objects (GkdSecretService *self)
3437+{
3438+ g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
3439+ return self->objects;
3440+}
3441+
3442+DBusConnection*
3443+gkd_secret_service_get_connection (GkdSecretService *self)
3444+{
3445+ g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
3446+ return self->connection;
3447+}
3448+
3449+GckSlot*
3450+gkd_secret_service_get_pkcs11_slot (GkdSecretService *self)
3451+{
3452+ g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
3453+ return gkd_secret_objects_get_pkcs11_slot (self->objects);
3454+}
3455+
3456+static gboolean
3457+log_into_pkcs11_session (GckSession *session, GError **error)
3458+{
3459+ GckSessionInfo *sess;
3460+ GckTokenInfo *info;
3461+ GckSlot *slot;
3462+ gboolean login;
3463+
3464+ /* Perform the necessary 'user' login to secrets token. Doesn't unlock anything */
3465+ slot = gck_session_get_slot (session);
3466+ info = gck_slot_get_token_info (slot);
3467+ login = info && (info->flags & CKF_LOGIN_REQUIRED);
3468+ gck_token_info_free (info);
3469+ g_object_unref (slot);
3470+
3471+ if (login) {
3472+ sess = gck_session_get_info (session);
3473+ if (sess->state == CKS_RO_USER_FUNCTIONS ||
3474+ sess->state == CKS_RW_USER_FUNCTIONS)
3475+ login = FALSE;
3476+ gck_session_info_free (sess);
3477+ }
3478+
3479+ if (login && !gck_session_login (session, CKU_USER, NULL, 0, NULL, error))
3480+ return FALSE;
3481+
3482+ return TRUE;
3483+}
3484+
3485+GckSession*
3486+gkd_secret_service_get_pkcs11_session (GkdSecretService *self, const gchar *caller)
3487+{
3488+ ServiceClient *client;
3489+ GError *error = NULL;
3490+ GckSlot *slot;
3491+
3492+ g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
3493+ g_return_val_if_fail (caller, NULL);
3494+
3495+ client = g_hash_table_lookup (self->clients, caller);
3496+ g_return_val_if_fail (client, NULL);
3497+
3498+ /* Open a new session if necessary */
3499+ if (!client->pkcs11_session) {
3500+ slot = gkd_secret_service_get_pkcs11_slot (self);
3501+ client->pkcs11_session = gck_slot_open_session_full (slot, GCK_SESSION_READ_WRITE,
3502+ CKF_G_APPLICATION_SESSION, &client->app,
3503+ NULL, NULL, &error);
3504+ if (!client->pkcs11_session) {
3505+ g_warning ("couldn't open pkcs11 session for secret service: %s",
3506+ egg_error_message (error));
3507+ g_clear_error (&error);
3508+ return NULL;
3509+ }
3510+
3511+ if (!log_into_pkcs11_session (client->pkcs11_session, &error)) {
3512+ g_warning ("couldn't log in to pkcs11 session for secret service: %s",
3513+ egg_error_message (error));
3514+ g_clear_error (&error);
3515+ g_object_unref (client->pkcs11_session);
3516+ client->pkcs11_session = NULL;
3517+ return NULL;
3518+ }
3519+ }
3520+
3521+ return client->pkcs11_session;
3522+}
3523+
3524+GckSession*
3525+gkd_secret_service_internal_pkcs11_session (GkdSecretService *self)
3526+{
3527+ GError *error = NULL;
3528+ GckSlot *slot;
3529+
3530+ g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
3531+
3532+ if (self->internal_session)
3533+ return self->internal_session;
3534+
3535+ slot = gkd_secret_service_get_pkcs11_slot (self);
3536+ self->internal_session = gck_slot_open_session_full (slot, GCK_SESSION_READ_WRITE,
3537+ 0, NULL, NULL, NULL, &error);
3538+ if (!self->internal_session) {
3539+ g_warning ("couldn't open pkcs11 session for secret service: %s",
3540+ egg_error_message (error));
3541+ g_clear_error (&error);
3542+ return NULL;
3543+ }
3544+
3545+ if (!log_into_pkcs11_session (self->internal_session, &error)) {
3546+ g_warning ("couldn't log in to pkcs11 session for secret service: %s",
3547+ egg_error_message (error));
3548+ g_clear_error (&error);
3549+ g_object_unref (self->internal_session);
3550+ self->internal_session = NULL;
3551+ return NULL;
3552+ }
3553+
3554+ return self->internal_session;
3555+}
3556+
3557+GkdSecretSession*
3558+gkd_secret_service_lookup_session (GkdSecretService *self, const gchar *path,
3559+ const gchar *caller)
3560+{
3561+ ServiceClient *client;
3562+ gpointer object;
3563+
3564+ g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
3565+ g_return_val_if_fail (path, NULL);
3566+ g_return_val_if_fail (caller, NULL);
3567+
3568+ client = g_hash_table_lookup (self->clients, caller);
3569+ g_return_val_if_fail (client, NULL);
3570+
3571+ object = g_hash_table_lookup (client->dispatch, path);
3572+ if (object == NULL || !GKD_SECRET_IS_SESSION (object))
3573+ return NULL;
3574+
3575+ return GKD_SECRET_SESSION (object);
3576+}
3577+
3578+void
3579+gkd_secret_service_close_session (GkdSecretService *self, GkdSecretSession *session)
3580+{
3581+ ServiceClient *client;
3582+ const gchar *caller;
3583+ const gchar *path;
3584+
3585+ g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
3586+ g_return_if_fail (GKD_SECRET_IS_SESSION (session));
3587+
3588+ caller = gkd_secret_session_get_caller (session);
3589+ client = g_hash_table_lookup (self->clients, caller);
3590+ g_return_if_fail (client);
3591+
3592+ path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (session));
3593+ g_hash_table_remove (client->dispatch, path);
3594+}
3595+
3596+const gchar*
3597+gkd_secret_service_get_alias (GkdSecretService *self, const gchar *alias)
3598+{
3599+ const gchar *identifier;
3600+
3601+ g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
3602+ g_return_val_if_fail (alias != NULL, NULL);
3603+
3604+ identifier = g_hash_table_lookup (self->aliases, alias);
3605+ if (!identifier) {
3606+ if (g_str_equal (alias, "default")) {
3607+ update_default (self, TRUE);
3608+ identifier = g_hash_table_lookup (self->aliases, alias);
3609+
3610+ /* Default to to 'login' if no default keyring */
3611+ if (identifier == NULL) {
3612+ identifier = "login";
3613+ g_hash_table_replace (self->aliases, g_strdup (alias),
3614+ g_strdup (identifier));
3615+ }
3616+
3617+ } else if (g_str_equal (alias, "session")) {
3618+ identifier = "session";
3619+ g_hash_table_replace (self->aliases, g_strdup (alias),
3620+ g_strdup (identifier));
3621+
3622+ /* TODO: We should be using CKA_G_LOGIN_COLLECTION */
3623+ } else if (g_str_equal (alias, "login")) {
3624+ identifier = "login";
3625+ g_hash_table_replace (self->aliases, g_strdup (alias),
3626+ g_strdup (identifier));
3627+ }
3628+ }
3629+
3630+ return identifier;
3631+}
3632+
3633+void
3634+gkd_secret_service_set_alias (GkdSecretService *self, const gchar *alias,
3635+ const gchar *identifier)
3636+{
3637+ g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
3638+ g_return_if_fail (alias);
3639+
3640+ g_hash_table_replace (self->aliases, g_strdup (alias), g_strdup (identifier));
3641+
3642+ if (g_str_equal (alias, "default"))
3643+ store_default (self);
3644+}
3645+
3646+void
3647+gkd_secret_service_publish_dispatch (GkdSecretService *self, const gchar *caller,
3648+ GkdSecretDispatch *object)
3649+{
3650+ ServiceClient *client;
3651+ const gchar *path;
3652+
3653+ g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
3654+ g_return_if_fail (caller);
3655+ g_return_if_fail (GKD_SECRET_IS_DISPATCH (object));
3656+
3657+ /* Take ownership of the session */
3658+ client = g_hash_table_lookup (self->clients, caller);
3659+ g_return_if_fail (client);
3660+ path = gkd_secret_dispatch_get_object_path (object);
3661+ g_return_if_fail (!g_hash_table_lookup (client->dispatch, path));
3662+ g_hash_table_replace (client->dispatch, (gpointer)path, g_object_ref (object));
3663+}
3664+
3665+static void
3666+emit_collections_properties_changed (GkdSecretService *self)
3667+{
3668+ const gchar *iface = SECRET_SERVICE_INTERFACE;
3669+ DBusMessage *message;
3670+ DBusMessageIter array;
3671+ DBusMessageIter iter;
3672+
3673+ message = dbus_message_new_signal (SECRET_SERVICE_PATH,
3674+ DBUS_INTERFACE_PROPERTIES,
3675+ "PropertiesChanged");
3676+
3677+ dbus_message_iter_init_append (message, &iter);
3678+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &iface);
3679+ service_append_all_properties (self, &iter);
3680+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &array);
3681+ dbus_message_iter_close_container (&iter, &array);
3682+
3683+ if (!dbus_connection_send (self->connection, message, NULL))
3684+ g_return_if_reached ();
3685+ dbus_message_unref (message);
3686+}
3687+
3688+void
3689+gkd_secret_service_emit_collection_created (GkdSecretService *self,
3690+ const gchar *collection_path)
3691+{
3692+ DBusMessage *message;
3693+
3694+ g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
3695+ g_return_if_fail (collection_path != NULL);
3696+
3697+ message = dbus_message_new_signal (SECRET_SERVICE_PATH,
3698+ SECRET_SERVICE_INTERFACE,
3699+ "CollectionCreated");
3700+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &collection_path,
3701+ DBUS_TYPE_INVALID);
3702+
3703+ if (!dbus_connection_send (self->connection, message, NULL))
3704+ g_return_if_reached ();
3705+ dbus_message_unref (message);
3706+
3707+ emit_collections_properties_changed (self);
3708+}
3709+
3710+void
3711+gkd_secret_service_emit_collection_deleted (GkdSecretService *self,
3712+ const gchar *collection_path)
3713+{
3714+ DBusMessage *message;
3715+
3716+ g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
3717+ g_return_if_fail (collection_path != NULL);
3718+
3719+ message = dbus_message_new_signal (SECRET_SERVICE_PATH,
3720+ SECRET_SERVICE_INTERFACE,
3721+ "CollectionDeleted");
3722+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &collection_path,
3723+ DBUS_TYPE_INVALID);
3724+
3725+ if (!dbus_connection_send (self->connection, message, NULL))
3726+ g_return_if_reached ();
3727+ dbus_message_unref (message);
3728+
3729+ emit_collections_properties_changed (self);
3730+}
3731
3732=== modified file '.pc/applied-patches'
3733--- .pc/applied-patches 2012-05-16 17:39:27 +0000
3734+++ .pc/applied-patches 2013-03-14 13:26:21 +0000
3735@@ -1,2 +1,4 @@
3736+00git_fix_searchitems_method.patch
3737+00git_fix_introspection.patch
3738 03_kfreebsd.patch
3739 04_nodisplay_autostart.patch
3740
3741=== modified file 'daemon/dbus/gkd-secret-introspect.c'
3742--- daemon/dbus/gkd-secret-introspect.c 2012-05-16 17:39:27 +0000
3743+++ daemon/dbus/gkd-secret-introspect.c 2013-03-14 13:26:21 +0000
3744@@ -63,7 +63,7 @@
3745 " <interface name='org.freedesktop.Secret.Collection'>\n"
3746 " <property name='Items' type='ao' access='read'/>\n"
3747 " <property name='Label' type='s' access='readwrite'/>\n"
3748- " <property name='Locked' type='s' access='read'/>\n"
3749+ " <property name='Locked' type='b' access='read'/>\n"
3750 " <property name='Created' type='t' access='read'/>\n"
3751 " <property name='Modified' type='t' access='read'/>\n"
3752 " <method name='Delete'>\n"
3753@@ -71,8 +71,7 @@
3754 " </method>\n"
3755 " <method name='SearchItems'>\n"
3756 " <arg name='attributes' type='a{ss}' direction='in'/>\n"
3757- " <arg name='unlocked' type='ao' direction='out'/>\n"
3758- " <arg name='locked' type='ao' direction='out'/>\n"
3759+ " <arg name='results' type='ao' direction='out'/>\n"
3760 " </method>\n"
3761 " <method name='CreateItem'>\n"
3762 " <arg name='props' type='a{sv}' direction='in'/>\n"
3763
3764=== modified file 'daemon/dbus/gkd-secret-objects.c'
3765--- daemon/dbus/gkd-secret-objects.c 2013-03-07 11:39:17 +0000
3766+++ daemon/dbus/gkd-secret-objects.c 2013-03-14 13:26:21 +0000
3767@@ -542,7 +542,7 @@
3768 static DBusMessage*
3769 collection_method_search_items (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
3770 {
3771- return gkd_secret_objects_handle_search_items (self, message, dbus_message_get_path (message));
3772+ return gkd_secret_objects_handle_search_items (self, message, dbus_message_get_path (message), FALSE);
3773 }
3774
3775 static GckObject*
3776@@ -1314,8 +1314,10 @@
3777 }
3778
3779 DBusMessage*
3780-gkd_secret_objects_handle_search_items (GkdSecretObjects *self, DBusMessage *message,
3781- const gchar *base)
3782+gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
3783+ DBusMessage *message,
3784+ const gchar *base,
3785+ gboolean separate_locked)
3786 {
3787 GckBuilder builder = GCK_BUILDER_INIT;
3788 DBusMessageIter iter;
3789@@ -1385,23 +1387,31 @@
3790 items = gck_objects_from_handle_array (session, data, n_data / sizeof (CK_OBJECT_HANDLE));
3791 g_free (data);
3792
3793+ /* Prepare the reply message */
3794+ reply = dbus_message_new_method_return (message);
3795+ dbus_message_iter_init_append (reply, &iter);
3796+
3797 /* Filter out the locked items */
3798- item_cleanup_search_results (session, items, &locked, &unlocked);
3799-
3800- /* Prepare the reply message */
3801- reply = dbus_message_new_method_return (message);
3802- dbus_message_iter_init_append (reply, &iter);
3803-
3804- dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
3805- objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_iter, &array);
3806- dbus_message_iter_close_container (&iter, &array);
3807-
3808- dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
3809- objects_foreach_item (self, locked, NULL, on_object_path_append_to_iter, &array);
3810- dbus_message_iter_close_container (&iter, &array);
3811-
3812- g_list_free (locked);
3813- g_list_free (unlocked);
3814+ if (separate_locked) {
3815+ item_cleanup_search_results (session, items, &locked, &unlocked);
3816+
3817+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
3818+ objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_iter, &array);
3819+ dbus_message_iter_close_container (&iter, &array);
3820+
3821+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
3822+ objects_foreach_item (self, locked, NULL, on_object_path_append_to_iter, &array);
3823+ dbus_message_iter_close_container (&iter, &array);
3824+
3825+ g_list_free (locked);
3826+ g_list_free (unlocked);
3827+
3828+ } else {
3829+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
3830+ objects_foreach_item (self, items, NULL, on_object_path_append_to_iter, &array);
3831+ dbus_message_iter_close_container (&iter, &array);
3832+ }
3833+
3834 gck_list_unref_free (items);
3835
3836 return reply;
3837
3838=== modified file 'daemon/dbus/gkd-secret-objects.h'
3839--- daemon/dbus/gkd-secret-objects.h 2012-08-13 12:39:40 +0000
3840+++ daemon/dbus/gkd-secret-objects.h 2013-03-14 13:26:21 +0000
3841@@ -55,7 +55,8 @@
3842
3843 DBusMessage* gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
3844 DBusMessage *message,
3845- const gchar *base);
3846+ const gchar *base,
3847+ gboolean separate_locked);
3848
3849 DBusMessage* gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self,
3850 DBusMessage *message);
3851
3852=== modified file 'daemon/dbus/gkd-secret-service.c'
3853--- daemon/dbus/gkd-secret-service.c 2012-08-24 10:32:10 +0000
3854+++ daemon/dbus/gkd-secret-service.c 2013-03-14 13:26:21 +0000
3855@@ -913,7 +913,7 @@
3856
3857 /* org.freedesktop.Secret.Service.SearchItems() */
3858 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "SearchItems"))
3859- return gkd_secret_objects_handle_search_items (self->objects, message, NULL);
3860+ return gkd_secret_objects_handle_search_items (self->objects, message, NULL, TRUE);
3861
3862 /* org.freedesktop.Secret.Service.GetSecrets() */
3863 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "GetSecrets"))
3864
3865=== modified file 'debian/changelog'
3866--- debian/changelog 2013-03-07 11:39:17 +0000
3867+++ debian/changelog 2013-03-14 13:26:21 +0000
3868@@ -1,3 +1,12 @@
3869+gnome-keyring (3.6.3-0ubuntu2) raring; urgency=low
3870+
3871+ * debian/patches/00git_fix_searchitems_method.patch:
3872+ Upstream patch to fix return value of Collection.SearchItems().
3873+ * debian/patches/00git_fix_introspection.patch:
3874+ Upstream patch to fix introspection of some D-Bus methods.
3875+
3876+ -- Dmitry Shachnev <mitya57@ubuntu.com> Thu, 14 Mar 2013 17:18:23 +0400
3877+
3878 gnome-keyring (3.6.3-0ubuntu1) raring; urgency=low
3879
3880 * New upstream release
3881
3882=== added file 'debian/patches/00git_fix_introspection.patch'
3883--- debian/patches/00git_fix_introspection.patch 1970-01-01 00:00:00 +0000
3884+++ debian/patches/00git_fix_introspection.patch 2013-03-14 13:26:21 +0000
3885@@ -0,0 +1,26 @@
3886+Author: Dmitry Shachnev <mitya57@ubuntu.com>
3887+Description: Fix introspection of some D-Bus methods
3888+Forwarded: yes
3889+Last-Update: 2013-03-10
3890+
3891+--- a/daemon/dbus/gkd-secret-introspect.c
3892++++ b/daemon/dbus/gkd-secret-introspect.c
3893+@@ -63,7 +63,7 @@
3894+ " <interface name='org.freedesktop.Secret.Collection'>\n"
3895+ " <property name='Items' type='ao' access='read'/>\n"
3896+ " <property name='Label' type='s' access='readwrite'/>\n"
3897+- " <property name='Locked' type='s' access='read'/>\n"
3898++ " <property name='Locked' type='b' access='read'/>\n"
3899+ " <property name='Created' type='t' access='read'/>\n"
3900+ " <property name='Modified' type='t' access='read'/>\n"
3901+ " <method name='Delete'>\n"
3902+@@ -71,8 +71,7 @@
3903+ " </method>\n"
3904+ " <method name='SearchItems'>\n"
3905+ " <arg name='attributes' type='a{ss}' direction='in'/>\n"
3906+- " <arg name='unlocked' type='ao' direction='out'/>\n"
3907+- " <arg name='locked' type='ao' direction='out'/>\n"
3908++ " <arg name='results' type='ao' direction='out'/>\n"
3909+ " </method>\n"
3910+ " <method name='CreateItem'>\n"
3911+ " <arg name='props' type='a{sv}' direction='in'/>\n"
3912
3913=== added file 'debian/patches/00git_fix_searchitems_method.patch'
3914--- debian/patches/00git_fix_searchitems_method.patch 1970-01-01 00:00:00 +0000
3915+++ debian/patches/00git_fix_searchitems_method.patch 2013-03-14 13:26:21 +0000
3916@@ -0,0 +1,99 @@
3917+Description: Only return one object path list from Collection.SearchItems()
3918+ In the Secret Service dbus interface the SearchItems method of the
3919+ Collection interface only returns one list of object paths, unlike
3920+ SearchItems on the Service interface which splits its return values
3921+ by locked and unlocked items.
3922+Origin: upstream, https://git.gnome.org/browse/gnome-keyring/commit/?id=ddb87ccad9
3923+Last-Update: 2013-03-10
3924+
3925+--- a/daemon/dbus/gkd-secret-objects.c
3926++++ b/daemon/dbus/gkd-secret-objects.c
3927+@@ -542,7 +542,7 @@
3928+ static DBusMessage*
3929+ collection_method_search_items (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
3930+ {
3931+- return gkd_secret_objects_handle_search_items (self, message, dbus_message_get_path (message));
3932++ return gkd_secret_objects_handle_search_items (self, message, dbus_message_get_path (message), FALSE);
3933+ }
3934+
3935+ static GckObject*
3936+@@ -1314,8 +1314,10 @@
3937+ }
3938+
3939+ DBusMessage*
3940+-gkd_secret_objects_handle_search_items (GkdSecretObjects *self, DBusMessage *message,
3941+- const gchar *base)
3942++gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
3943++ DBusMessage *message,
3944++ const gchar *base,
3945++ gboolean separate_locked)
3946+ {
3947+ GckBuilder builder = GCK_BUILDER_INIT;
3948+ DBusMessageIter iter;
3949+@@ -1385,23 +1387,31 @@
3950+ items = gck_objects_from_handle_array (session, data, n_data / sizeof (CK_OBJECT_HANDLE));
3951+ g_free (data);
3952+
3953+- /* Filter out the locked items */
3954+- item_cleanup_search_results (session, items, &locked, &unlocked);
3955+-
3956+ /* Prepare the reply message */
3957+ reply = dbus_message_new_method_return (message);
3958+ dbus_message_iter_init_append (reply, &iter);
3959+
3960+- dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
3961+- objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_iter, &array);
3962+- dbus_message_iter_close_container (&iter, &array);
3963+-
3964+- dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
3965+- objects_foreach_item (self, locked, NULL, on_object_path_append_to_iter, &array);
3966+- dbus_message_iter_close_container (&iter, &array);
3967++ /* Filter out the locked items */
3968++ if (separate_locked) {
3969++ item_cleanup_search_results (session, items, &locked, &unlocked);
3970++
3971++ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
3972++ objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_iter, &array);
3973++ dbus_message_iter_close_container (&iter, &array);
3974++
3975++ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
3976++ objects_foreach_item (self, locked, NULL, on_object_path_append_to_iter, &array);
3977++ dbus_message_iter_close_container (&iter, &array);
3978++
3979++ g_list_free (locked);
3980++ g_list_free (unlocked);
3981++
3982++ } else {
3983++ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
3984++ objects_foreach_item (self, items, NULL, on_object_path_append_to_iter, &array);
3985++ dbus_message_iter_close_container (&iter, &array);
3986++ }
3987+
3988+- g_list_free (locked);
3989+- g_list_free (unlocked);
3990+ gck_list_unref_free (items);
3991+
3992+ return reply;
3993+--- a/daemon/dbus/gkd-secret-objects.h
3994++++ b/daemon/dbus/gkd-secret-objects.h
3995+@@ -55,7 +55,8 @@
3996+
3997+ DBusMessage* gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
3998+ DBusMessage *message,
3999+- const gchar *base);
4000++ const gchar *base,
4001++ gboolean separate_locked);
4002+
4003+ DBusMessage* gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self,
4004+ DBusMessage *message);
4005+--- a/daemon/dbus/gkd-secret-service.c
4006++++ b/daemon/dbus/gkd-secret-service.c
4007+@@ -913,7 +913,7 @@
4008+
4009+ /* org.freedesktop.Secret.Service.SearchItems() */
4010+ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "SearchItems"))
4011+- return gkd_secret_objects_handle_search_items (self->objects, message, NULL);
4012++ return gkd_secret_objects_handle_search_items (self->objects, message, NULL, TRUE);
4013+
4014+ /* org.freedesktop.Secret.Service.GetSecrets() */
4015+ if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "GetSecrets"))
4016
4017=== modified file 'debian/patches/series'
4018--- debian/patches/series 2012-05-16 17:39:27 +0000
4019+++ debian/patches/series 2013-03-14 13:26:21 +0000
4020@@ -1,2 +1,4 @@
4021+00git_fix_searchitems_method.patch
4022+00git_fix_introspection.patch
4023 03_kfreebsd.patch
4024 04_nodisplay_autostart.patch

Subscribers

People subscribed via source and target branches