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
=== added directory '.pc/00git_fix_introspection.patch'
=== added directory '.pc/00git_fix_introspection.patch/daemon'
=== added directory '.pc/00git_fix_introspection.patch/daemon/dbus'
=== added file '.pc/00git_fix_introspection.patch/daemon/dbus/gkd-secret-introspect.c'
--- .pc/00git_fix_introspection.patch/daemon/dbus/gkd-secret-introspect.c 1970-01-01 00:00:00 +0000
+++ .pc/00git_fix_introspection.patch/daemon/dbus/gkd-secret-introspect.c 2013-03-14 13:26:21 +0000
@@ -0,0 +1,285 @@
1/*
2 * gnome-keyring
3 *
4 * Copyright (C) 2011 Collabora Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 *
21 * Author: Stef Walter <stefw@collabora.co.uk>
22 */
23
24#include "config.h"
25
26#include "gkd-secret-introspect.h"
27
28const gchar *gkd_secret_introspect_root =
29 "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
30 " 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
31 "<node>\n"
32 " <node name='org/freedesktop/secrets'/>\n"
33 "</node>\n";
34
35const gchar *gkd_secret_introspect_collection =
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 "\n"
40 " <interface name='org.freedesktop.DBus.Introspectable'>\n"
41 " <method name='Introspect'>\n"
42 " <arg name='data' direction='out' type='s'/>\n"
43 " </method>\n"
44 " </interface>\n"
45 "\n"
46 " <interface name='org.freedesktop.DBus.Properties'>\n"
47 " <method name='Get'>\n"
48 " <arg name='interface' direction='in' type='s'/>\n"
49 " <arg name='propname' direction='in' type='s'/>\n"
50 " <arg name='value' direction='out' type='v'/>\n"
51 " </method>\n"
52 " <method name='Set'>\n"
53 " <arg name='interface' direction='in' type='s'/>\n"
54 " <arg name='propname' direction='in' type='s'/>\n"
55 " <arg name='value' direction='in' type='v'/>\n"
56 " </method>\n"
57 " <method name='GetAll'>\n"
58 " <arg name='interface' direction='in' type='s'/>\n"
59 " <arg name='props' direction='out' type='a{sv}'/>\n"
60 " </method>\n"
61 " </interface>\n"
62 "\n"
63 " <interface name='org.freedesktop.Secret.Collection'>\n"
64 " <property name='Items' type='ao' access='read'/>\n"
65 " <property name='Label' type='s' access='readwrite'/>\n"
66 " <property name='Locked' type='s' access='read'/>\n"
67 " <property name='Created' type='t' access='read'/>\n"
68 " <property name='Modified' type='t' access='read'/>\n"
69 " <method name='Delete'>\n"
70 " <arg name='prompt' type='o' direction='out'/>\n"
71 " </method>\n"
72 " <method name='SearchItems'>\n"
73 " <arg name='attributes' type='a{ss}' direction='in'/>\n"
74 " <arg name='unlocked' type='ao' direction='out'/>\n"
75 " <arg name='locked' type='ao' direction='out'/>\n"
76 " </method>\n"
77 " <method name='CreateItem'>\n"
78 " <arg name='props' type='a{sv}' direction='in'/>\n"
79 " <arg name='secret' type='(oayays)' direction='in'/>\n"
80 " <arg name='replace' type='b' direction='in'/>\n"
81 " <arg name='item' type='o' direction='out'/>\n"
82 " <arg name='prompt' type='o' direction='out'/>\n"
83 " </method>\n"
84 " <signal name='ItemCreated'>\n"
85 " <arg name='item' type='o'/>\n"
86 " </signal>\n"
87 " <signal name='ItemDeleted'>\n"
88 " <arg name='item' type='o'/>\n"
89 " </signal>\n"
90 " <signal name='ItemChanged'>\n"
91 " <arg name='item' type='o'/>\n"
92 " </signal>\n"
93 " </interface>\n"
94 "\n"
95 "<!--@children@-->"
96 "</node>\n";
97
98const gchar *gkd_secret_introspect_item =
99 "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
100 " 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
101 "<node>\n"
102 "\n"
103 " <interface name='org.freedesktop.DBus.Introspectable'>\n"
104 " <method name='Introspect'>\n"
105 " <arg name='data' direction='out' type='s'/>\n"
106 " </method>\n"
107 " </interface>\n"
108 "\n"
109 " <interface name='org.freedesktop.DBus.Properties'>\n"
110 " <method name='Get'>\n"
111 " <arg name='interface' direction='in' type='s'/>\n"
112 " <arg name='propname' direction='in' type='s'/>\n"
113 " <arg name='value' direction='out' type='v'/>\n"
114 " </method>\n"
115 " <method name='Set'>\n"
116 " <arg name='interface' direction='in' type='s'/>\n"
117 " <arg name='propname' direction='in' type='s'/>\n"
118 " <arg name='value' direction='in' type='v'/>\n"
119 " </method>\n"
120 " <method name='GetAll'>\n"
121 " <arg name='interface' direction='in' type='s'/>\n"
122 " <arg name='props' direction='out' type='a{sv}'/>\n"
123 " </method>\n"
124 " </interface>\n"
125 "\n"
126 " <interface name='org.freedesktop.Secret.Item'>\n"
127 " <property name='Locked' type='b' access='read'/>\n"
128 " <property name='Attributes' type='a{ss}' access='readwrite'/>\n"
129 " <property name='Label' type='s' access='readwrite'/>\n"
130 " <property name='Type' type='s' access='readwrite'/>\n"
131 " <property name='Created' type='t' access='read'/>\n"
132 " <property name='Modified' type='t' access='read'/>\n"
133 " <method name='Delete'>\n"
134 " <arg name='prompt' type='o' direction='out'/>\n"
135 " </method>\n"
136 " <method name='GetSecret'>\n"
137 " <arg name='session' type='o' direction='in'/>\n"
138 " <arg name='secret' type='(oayays)' direction='out'/>\n"
139 " </method>\n"
140 " <method name='SetSecret'>\n"
141 " <arg name='secret' type='(oayays)' direction='in'/>\n"
142 " </method>\n"
143 " </interface>\n"
144 "\n"
145 "</node>\n";
146
147const gchar *gkd_secret_introspect_prompt =
148 "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
149 " 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
150 "<node>\n"
151 "\n"
152 " <interface name='org.freedesktop.DBus.Introspectable'>\n"
153 " <method name='Introspect'>\n"
154 " <arg name='data' direction='out' type='s'/>\n"
155 " </method>\n"
156 " </interface>\n"
157 "\n"
158 " <interface name='org.freedesktop.Secret.Prompt'>\n"
159 " <method name='Prompt'>\n"
160 " <arg name='window-id' type='s' direction='in'/>\n"
161 " </method>\n"
162 " <method name='Dismiss'>\n"
163 " </method>\n"
164 " <signal name='Completed'>\n"
165 " <arg name='dismissed' type='b'/>\n"
166 " <arg name='result' type='v'/>\n"
167 " </signal>\n"
168 " </interface>\n"
169 "\n"
170 "</node>\n";
171
172const gchar *gkd_secret_introspect_service =
173 "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
174 " 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
175 "<node>\n"
176 "\n"
177 " <interface name='org.freedesktop.DBus.Introspectable'>\n"
178 " <method name='Introspect'>\n"
179 " <arg name='data' direction='out' type='s'/>\n"
180 " </method>\n"
181 " </interface>\n"
182 "\n"
183 " <interface name='org.freedesktop.DBus.Properties'>\n"
184 " <method name='Get'>\n"
185 " <arg name='interface' direction='in' type='s'/>\n"
186 " <arg name='propname' direction='in' type='s'/>\n"
187 " <arg name='value' direction='out' type='v'/>\n"
188 " </method>\n"
189 " <method name='Set'>\n"
190 " <arg name='interface' direction='in' type='s'/>\n"
191 " <arg name='propname' direction='in' type='s'/>\n"
192 " <arg name='value' direction='in' type='v'/>\n"
193 " </method>\n"
194 " <method name='GetAll'>\n"
195 " <arg name='interface' direction='in' type='s'/>\n"
196 " <arg name='props' direction='out' type='a{sv}'/>\n"
197 " </method>\n"
198 " </interface>\n"
199 "\n"
200 " <interface name='org.freedesktop.Secret.Service'>\n"
201 "\n"
202 " <property name='Collections' type='ao' access='read'/>\n"
203 "\n"
204 " <method name='OpenSession'>\n"
205 " <arg name='algorithm' type='s' direction='in'/>\n"
206 " <arg name='input' type='v' direction='in'/>\n"
207 " <arg name='output' type='v' direction='out'/>\n"
208 " <arg name='result' type='o' direction='out'/>\n"
209 " </method>\n"
210 "\n"
211 " <method name='CreateCollection'>\n"
212 " <arg name='properties' type='a{sv}' direction='in'/>\n"
213 " <arg name='alias' type='s' direction='in'/>\n"
214 " <arg name='collection' type='o' direction='out'/>\n"
215 " <arg name='prompt' type='o' direction='out'/>\n"
216 " </method>\n"
217 "\n"
218 " <method name='SearchItems'>\n"
219 " <arg name='attributes' type='a{ss}' direction='in'/>\n"
220 " <arg name='unlocked' type='ao' direction='out'/>\n"
221 " <arg name='locked' type='ao' direction='out'/>\n"
222 " </method>\n"
223 "\n"
224 " <method name='Unlock'>\n"
225 " <arg name='objects' type='ao' direction='in'/>\n"
226 " <arg name='unlocked' type='ao' direction='out'/>\n"
227 " <arg name='prompt' type='o' direction='out'/>\n"
228 " </method>\n"
229 "\n"
230 " <method name='Lock'>\n"
231 " <arg name='objects' type='ao' direction='in'/>\n"
232 " <arg name='locked' type='ao' direction='out'/>\n"
233 " <arg name='Prompt' type='o' direction='out'/>\n"
234 " </method>\n"
235 "\n"
236 " <method name='GetSecrets'>\n"
237 " <arg name='items' type='ao' direction='in'/>\n"
238 " <arg name='session' type='o' direction='in'/>\n"
239 " <arg name='secrets' type='a{o(oayays)}' direction='out'/>\n"
240 " </method>\n"
241 "\n"
242 " <method name='ReadAlias'>\n"
243 " <arg name='name' type='s' direction='in'/>\n"
244 " <arg name='collection' type='o' direction='out'/>\n"
245 " </method>\n"
246 "\n"
247 " <method name='SetAlias'>\n"
248 " <arg name='name' type='s' direction='in'/>\n"
249 " <arg name='collection' type='o' direction='in'/>\n"
250 " </method>\n"
251 "\n"
252 " <signal name='CollectionCreated'>\n"
253 " <arg name='collection' type='o'/>\n"
254 " </signal>\n"
255 "\n"
256 " <signal name='CollectionDeleted'>\n"
257 " <arg name='collection' type='o'/>\n"
258 " </signal>\n"
259 "\n"
260 " <signal name='CollectionChanged'>\n"
261 " <arg name='collection' type='o'/>\n"
262 " </signal>\n"
263 "\n"
264 " </interface>\n"
265 "\n"
266 "<!--@children@-->"
267 "</node>\n";
268
269const gchar *gkd_secret_introspect_session =
270 "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
271 " 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
272 "<node>\n"
273 "\n"
274 " <interface name='org.freedesktop.DBus.Introspectable'>\n"
275 " <method name='Introspect'>\n"
276 " <arg name='data' direction='out' type='s'/>\n"
277 " </method>\n"
278 " </interface>\n"
279 "\n"
280 " <interface name='org.freedesktop.Secret.Session'>\n"
281 " <method name='Close'>\n"
282 " </method>\n"
283 " </interface>\n"
284 "\n"
285 "</node>\n";
0286
=== added directory '.pc/00git_fix_searchitems_method.patch'
=== added directory '.pc/00git_fix_searchitems_method.patch/daemon'
=== added directory '.pc/00git_fix_searchitems_method.patch/daemon/dbus'
=== added file '.pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.c'
--- .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.c 1970-01-01 00:00:00 +0000
+++ .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.c 2013-03-14 13:26:21 +0000
@@ -0,0 +1,1710 @@
1/*
2 * gnome-keyring
3 *
4 * Copyright (C) 2008 Stefan Walter
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include "config.h"
23
24#include "gkd-dbus-util.h"
25
26#include "gkd-secret-error.h"
27#include "gkd-secret-introspect.h"
28#include "gkd-secret-objects.h"
29#include "gkd-secret-property.h"
30#include "gkd-secret-secret.h"
31#include "gkd-secret-service.h"
32#include "gkd-secret-session.h"
33#include "gkd-secret-types.h"
34#include "gkd-secret-util.h"
35
36#include "egg/egg-error.h"
37
38#include "pkcs11/pkcs11i.h"
39
40#include <string.h>
41
42enum {
43 PROP_0,
44 PROP_PKCS11_SLOT,
45 PROP_SERVICE
46};
47
48struct _GkdSecretObjects {
49 GObject parent;
50 GkdSecretService *service;
51 GckSlot *pkcs11_slot;
52};
53
54static gchar * object_path_for_item (const gchar *base,
55 GckObject *item);
56
57static gchar * object_path_for_collection (GckObject *collection);
58
59static gchar * collection_path_for_item (GckObject *item);
60
61G_DEFINE_TYPE (GkdSecretObjects, gkd_secret_objects, G_TYPE_OBJECT);
62
63/* -----------------------------------------------------------------------------
64 * INTERNAL
65 */
66
67static gboolean
68parse_object_path (GkdSecretObjects *self, const gchar *path, gchar **collection, gchar **item)
69{
70 const gchar *replace;
71
72 g_assert (self);
73 g_assert (path);
74 g_assert (collection);
75
76 if (!gkd_secret_util_parse_path (path, collection, item))
77 return FALSE;
78
79 if (g_str_has_prefix (path, SECRET_ALIAS_PREFIX)) {
80 replace = gkd_secret_service_get_alias (self->service, *collection);
81 if (!replace) {
82 g_free (*collection);
83 *collection = NULL;
84 if (item) {
85 g_free (*item);
86 *item = NULL;
87 }
88 return FALSE;
89 }
90 g_free (*collection);
91 *collection = g_strdup (replace);
92 }
93
94 return TRUE;
95}
96
97static DBusMessage*
98object_property_get (GckObject *object, DBusMessage *message,
99 const gchar *prop_name)
100{
101 DBusMessageIter iter;
102 GError *error = NULL;
103 DBusMessage *reply;
104 GckAttribute attr;
105 gpointer value;
106 gsize length;
107
108 if (!gkd_secret_property_get_type (prop_name, &attr.type))
109 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
110 "Object does not have the '%s' property", prop_name);
111
112 /* Retrieve the actual attribute */
113 attr.value = value = gck_object_get_data (object, attr.type, NULL, &length, &error);
114 if (error != NULL) {
115 reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
116 "Couldn't retrieve '%s' property: %s",
117 prop_name, egg_error_message (error));
118 g_clear_error (&error);
119 return reply;
120 }
121
122 /* Marshall the data back out */
123 attr.length = length;
124 reply = dbus_message_new_method_return (message);
125 dbus_message_iter_init_append (reply, &iter);
126 gkd_secret_property_append_variant (&iter, &attr);
127 g_free (value);
128 return reply;
129}
130
131static DBusMessage*
132object_property_set (GckObject *object,
133 DBusMessage *message,
134 DBusMessageIter *iter,
135 const gchar *prop_name)
136{
137 GckBuilder builder = GCK_BUILDER_INIT;
138 DBusMessage *reply;
139 GError *error = NULL;
140 gulong attr_type;
141
142 g_return_val_if_fail (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_VARIANT, NULL);
143
144 /* What type of property is it? */
145 if (!gkd_secret_property_get_type (prop_name, &attr_type))
146 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
147 "Object does not have the '%s' property", prop_name);
148
149 /* Retrieve the actual attribute value */
150 if (!gkd_secret_property_parse_variant (iter, prop_name, &builder)) {
151 gck_builder_clear (&builder);
152 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
153 "The property type or value was invalid: %s", prop_name);
154 }
155
156 gck_object_set (object, gck_builder_end (&builder), NULL, &error);
157
158 if (error != NULL) {
159 if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
160 reply = dbus_message_new_error (message, SECRET_ERROR_IS_LOCKED,
161 "Cannot set property on a locked object");
162 else
163 reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
164 "Couldn't set '%s' property: %s",
165 prop_name, egg_error_message (error));
166 g_clear_error (&error);
167 return reply;
168 }
169
170 return dbus_message_new_method_return (message);
171}
172
173static DBusMessage*
174item_property_get (GckObject *object, DBusMessage *message)
175{
176 const gchar *interface;
177 const gchar *name;
178
179 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface,
180 DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
181 return NULL;
182
183 if (!gkd_dbus_interface_match (SECRET_ITEM_INTERFACE, interface))
184 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
185 "Object does not have properties on interface '%s'",
186 interface);
187
188 return object_property_get (object, message, name);
189}
190
191static DBusMessage*
192item_property_set (GkdSecretObjects *self,
193 GckObject *object,
194 DBusMessage *message)
195{
196 DBusMessageIter iter;
197 const char *interface;
198 const char *name;
199 DBusMessage *reply;
200
201 if (!dbus_message_has_signature (message, "ssv"))
202 return NULL;
203
204 dbus_message_iter_init (message, &iter);
205 dbus_message_iter_get_basic (&iter, &interface);
206 dbus_message_iter_next (&iter);
207 dbus_message_iter_get_basic (&iter, &name);
208 dbus_message_iter_next (&iter);
209
210 if (!gkd_dbus_interface_match (SECRET_ITEM_INTERFACE, interface))
211 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
212 "Object does not have properties on interface '%s'",
213 interface);
214
215 reply = object_property_set (object, message, &iter, name);
216
217 /* Notify everyone a property changed */
218 if (reply && dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
219 gkd_secret_objects_emit_item_changed (self, object, name, NULL);
220
221 return reply;
222}
223
224static DBusMessage*
225item_property_getall (GckObject *object, DBusMessage *message)
226{
227 GckAttributes *attrs;
228 DBusMessageIter iter;
229 DBusMessageIter array;
230 GError *error = NULL;
231 DBusMessage *reply;
232 const gchar *interface;
233
234 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID))
235 return NULL;
236
237 if (!gkd_dbus_interface_match (SECRET_ITEM_INTERFACE, interface))
238 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
239 "Object does not have properties on interface '%s'",
240 interface);
241
242 attrs = gck_object_get (object, NULL, &error,
243 CKA_LABEL,
244 CKA_G_SCHEMA,
245 CKA_G_LOCKED,
246 CKA_G_CREATED,
247 CKA_G_MODIFIED,
248 CKA_G_FIELDS,
249 GCK_INVALID);
250
251 if (error != NULL)
252 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
253 "Couldn't retrieve properties: %s",
254 egg_error_message (error));
255
256 reply = dbus_message_new_method_return (message);
257
258 dbus_message_iter_init_append (reply, &iter);
259 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
260 gkd_secret_property_append_all (&array, attrs);
261 dbus_message_iter_close_container (&iter, &array);
262 return reply;
263}
264
265static DBusMessage*
266item_method_delete (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
267{
268 GError *error = NULL;
269 gchar *collection_path;
270 gchar *item_path;
271 DBusMessage *reply;
272 const gchar *prompt;
273 GckObject *collection;
274
275 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INVALID))
276 return NULL;
277
278 collection_path = collection_path_for_item (object);
279 item_path = object_path_for_item (NULL, object);
280
281 if (gck_object_destroy (object, NULL, &error)) {
282 collection = gkd_secret_objects_lookup_collection (self, NULL, collection_path);
283 if (collection != NULL) {
284 gkd_secret_objects_emit_item_deleted (self, collection, item_path);
285 g_object_unref (collection);
286 }
287
288 prompt = "/"; /* No prompt necessary */
289 reply = dbus_message_new_method_return (message);
290 dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &prompt, DBUS_TYPE_INVALID);
291
292 } else {
293 if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
294 reply = dbus_message_new_error_printf (message, SECRET_ERROR_IS_LOCKED,
295 "Cannot delete a locked item");
296 else
297 reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
298 "Couldn't delete collection: %s",
299 egg_error_message (error));
300
301 g_clear_error (&error);
302 }
303
304 g_free (collection_path);
305 g_free (item_path);
306 return reply;
307}
308
309static DBusMessage*
310item_method_get_secret (GkdSecretObjects *self, GckObject *item, DBusMessage *message)
311{
312 DBusError derr = DBUS_ERROR_INIT;
313 GkdSecretSession *session;
314 GkdSecretSecret *secret;
315 DBusMessage *reply;
316 DBusMessageIter iter;
317 const char *path;
318
319 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
320 return NULL;
321
322 session = gkd_secret_service_lookup_session (self->service, path, dbus_message_get_sender (message));
323 if (session == NULL)
324 return dbus_message_new_error (message, SECRET_ERROR_NO_SESSION, "The session does not exist");
325
326 secret = gkd_secret_session_get_item_secret (session, item, &derr);
327 if (secret == NULL)
328 return gkd_secret_error_to_reply (message, &derr);
329
330 reply = dbus_message_new_method_return (message);
331 dbus_message_iter_init_append (reply, &iter);
332 gkd_secret_secret_append (secret, &iter);
333 gkd_secret_secret_free (secret);
334 return reply;
335}
336
337static DBusMessage*
338item_method_set_secret (GkdSecretObjects *self, GckObject *item, DBusMessage *message)
339{
340 DBusError derr = DBUS_ERROR_INIT;
341 DBusMessageIter iter;
342 GkdSecretSecret *secret;
343 const char *caller;
344
345 if (!dbus_message_has_signature (message, "(oayays)"))
346 return NULL;
347 dbus_message_iter_init (message, &iter);
348 secret = gkd_secret_secret_parse (self->service, message, &iter, &derr);
349 if (secret == NULL)
350 return gkd_secret_error_to_reply (message, &derr);
351
352 caller = dbus_message_get_sender (message);
353 g_return_val_if_fail (caller, NULL);
354
355 gkd_secret_session_set_item_secret (secret->session, item, secret, &derr);
356 gkd_secret_secret_free (secret);
357
358 if (dbus_error_is_set (&derr))
359 return gkd_secret_error_to_reply (message, &derr);
360
361 return dbus_message_new_method_return (message);
362}
363
364static DBusMessage*
365item_message_handler (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
366{
367 /* org.freedesktop.Secret.Item.Delete() */
368 if (dbus_message_is_method_call (message, SECRET_ITEM_INTERFACE, "Delete"))
369 return item_method_delete (self, object, message);
370
371 /* org.freedesktop.Secret.Session.GetSecret() */
372 else if (dbus_message_is_method_call (message, SECRET_ITEM_INTERFACE, "GetSecret"))
373 return item_method_get_secret (self, object, message);
374
375 /* org.freedesktop.Secret.Session.SetSecret() */
376 else if (dbus_message_is_method_call (message, SECRET_ITEM_INTERFACE, "SetSecret"))
377 return item_method_set_secret (self, object, message);
378
379 /* org.freedesktop.DBus.Properties.Get */
380 if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Get"))
381 return item_property_get (object, message);
382
383 /* org.freedesktop.DBus.Properties.Set */
384 else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Set"))
385 return item_property_set (self, object, message);
386
387 /* org.freedesktop.DBus.Properties.GetAll */
388 else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "GetAll"))
389 return item_property_getall (object, message);
390
391 else if (dbus_message_has_interface (message, DBUS_INTERFACE_INTROSPECTABLE))
392 return gkd_dbus_introspect_handle (message, gkd_secret_introspect_item, NULL);
393
394 return NULL;
395}
396
397static void
398item_cleanup_search_results (GckSession *session, GList *items,
399 GList **locked, GList **unlocked)
400{
401 GError *error = NULL;
402 gpointer value;
403 gsize n_value;
404 GList *l;
405
406 *locked = NULL;
407 *unlocked = NULL;
408
409 for (l = items; l; l = g_list_next (l)) {
410 value = gck_object_get_data (l->data, CKA_G_LOCKED, NULL, &n_value, &error);
411 if (value == NULL) {
412 if (!g_error_matches (error, GCK_ERROR, CKR_OBJECT_HANDLE_INVALID))
413 g_warning ("couldn't check if item is locked: %s", egg_error_message (error));
414 g_clear_error (&error);
415
416 /* Is not locked */
417 } if (n_value == 1 && *((CK_BBOOL*)value) == CK_FALSE) {
418 *unlocked = g_list_prepend (*unlocked, l->data);
419
420 /* Is locked */
421 } else {
422 *locked = g_list_prepend (*locked, l->data);
423 }
424
425 g_free (value);
426 }
427
428 *locked = g_list_reverse (*locked);
429 *unlocked = g_list_reverse (*unlocked);
430}
431
432static DBusMessage*
433collection_property_get (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
434{
435 DBusMessageIter iter;
436 DBusMessage *reply;
437 const gchar *interface;
438 const gchar *name;
439
440 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface,
441 DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
442 return NULL;
443
444 if (!gkd_dbus_interface_match (SECRET_COLLECTION_INTERFACE, interface))
445 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
446 "Object does not have properties on interface '%s'",
447 interface);
448
449 /* Special case, the Items property */
450 if (g_str_equal (name, "Items")) {
451 reply = dbus_message_new_method_return (message);
452 dbus_message_iter_init_append (reply, &iter);
453 gkd_secret_objects_append_item_paths (self, dbus_message_get_path (message), &iter, message);
454 return reply;
455 }
456
457 return object_property_get (object, message, name);
458}
459
460static DBusMessage*
461collection_property_set (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
462{
463 DBusMessageIter iter;
464 DBusMessage *reply;
465 const char *interface;
466 const char *name;
467
468 if (!dbus_message_has_signature (message, "ssv"))
469 return NULL;
470
471 dbus_message_iter_init (message, &iter);
472 dbus_message_iter_get_basic (&iter, &interface);
473 dbus_message_iter_next (&iter);
474 dbus_message_iter_get_basic (&iter, &name);
475 dbus_message_iter_next (&iter);
476
477 if (!gkd_dbus_interface_match (SECRET_COLLECTION_INTERFACE, interface))
478 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
479 "Object does not have properties on interface '%s'",
480 interface);
481
482 reply = object_property_set (object, message, &iter, name);
483
484 /* Notify everyone a property changed */
485 if (reply && dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
486 gkd_secret_objects_emit_collection_changed (self, object, name, NULL);
487
488 return reply;
489}
490
491static DBusMessage*
492collection_property_getall (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
493{
494 GckAttributes *attrs;
495 DBusMessageIter iter;
496 DBusMessageIter array;
497 DBusMessageIter dict;
498 GError *error = NULL;
499 DBusMessage *reply;
500 const gchar *name;
501 const gchar *interface;
502
503 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID))
504 return NULL;
505
506 if (!gkd_dbus_interface_match (SECRET_COLLECTION_INTERFACE, interface))
507 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
508 "Object does not have properties on interface '%s'",
509 interface);
510
511 attrs = gck_object_get (object, NULL, &error,
512 CKA_LABEL,
513 CKA_G_LOCKED,
514 CKA_G_CREATED,
515 CKA_G_MODIFIED,
516 GCK_INVALID);
517
518 if (error != NULL)
519 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
520 "Couldn't retrieve properties: %s",
521 egg_error_message (error));
522
523 reply = dbus_message_new_method_return (message);
524
525 dbus_message_iter_init_append (reply, &iter);
526 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
527
528 /* Append all the usual properties */
529 gkd_secret_property_append_all (&array, attrs);
530
531 /* Append the Items property */
532 dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
533 name = "Items";
534 dbus_message_iter_append_basic (&dict, DBUS_TYPE_STRING, &name);
535 gkd_secret_objects_append_item_paths (self, dbus_message_get_path (message), &dict, message);
536 dbus_message_iter_close_container (&array, &dict);
537
538 dbus_message_iter_close_container (&iter, &array);
539 return reply;
540}
541
542static DBusMessage*
543collection_method_search_items (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
544{
545 return gkd_secret_objects_handle_search_items (self, message, dbus_message_get_path (message));
546}
547
548static GckObject*
549collection_find_matching_item (GkdSecretObjects *self,
550 GckSession *session,
551 const gchar *identifier,
552 const GckAttribute *fields)
553{
554 GckBuilder builder = GCK_BUILDER_INIT;
555 GckObject *result = NULL;
556 GError *error = NULL;
557 GckObject *search;
558 gpointer data;
559 gsize n_data;
560
561 /* Find items matching the collection and fields */
562 gck_builder_add_attribute (&builder, fields);
563 gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
564 gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_SEARCH);
565 gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);
566
567 /* Create the search object */
568 search = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error);
569
570 if (error != NULL) {
571 g_warning ("couldn't search for matching item: %s", egg_error_message (error));
572 g_clear_error (&error);
573 return NULL;
574 }
575
576 /* Get the matched item handles, and delete the search object */
577 data = gck_object_get_data (search, CKA_G_MATCHED, NULL, &n_data, NULL);
578 gck_object_destroy (search, NULL, NULL);
579 g_object_unref (search);
580
581 if (n_data >= sizeof (CK_OBJECT_HANDLE))
582 result = gck_object_from_handle (session, *((CK_OBJECT_HANDLE_PTR)data));
583
584 g_free (data);
585 return result;
586}
587
588static gchar *
589object_path_for_item (const gchar *base,
590 GckObject *item)
591{
592 GError *error = NULL;
593 gpointer identifier;
594 gsize n_identifier;
595 gchar *alloc = NULL;
596 gchar *path = NULL;
597
598 if (base == NULL)
599 base = alloc = collection_path_for_item (item);
600
601 identifier = gck_object_get_data (item, CKA_ID, NULL, &n_identifier, &error);
602 if (identifier == NULL) {
603 g_warning ("couldn't get item identifier: %s", egg_error_message (error));
604 g_clear_error (&error);
605 path = NULL;
606
607 } else {
608 path = gkd_secret_util_build_path (base, identifier, n_identifier);
609 g_free (identifier);
610 }
611
612 g_free (alloc);
613 return path;
614}
615
616static gchar *
617collection_path_for_item (GckObject *item)
618{
619 GError *error = NULL;
620 gpointer identifier;
621 gsize n_identifier;
622 gchar *path = NULL;
623
624 identifier = gck_object_get_data (item, CKA_G_COLLECTION, NULL, &n_identifier, &error);
625 if (!identifier) {
626 g_warning ("couldn't get item collection identifier: %s", egg_error_message (error));
627 g_clear_error (&error);
628 return NULL;
629 }
630
631 path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
632 g_free (identifier);
633 return path;
634}
635
636static gchar *
637object_path_for_collection (GckObject *collection)
638{
639 GError *error = NULL;
640 gpointer identifier;
641 gsize n_identifier;
642 gchar *path = NULL;
643
644 identifier = gck_object_get_data (collection, CKA_ID, NULL, &n_identifier, &error);
645 if (identifier == NULL) {
646 g_warning ("couldn't get collection identifier: %s", egg_error_message (error));
647 g_clear_error (&error);
648 path = NULL;
649
650 } else {
651 path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
652 g_free (identifier);
653 }
654
655 return path;
656}
657
658static DBusMessage*
659collection_method_create_item (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
660{
661 GckBuilder builder = GCK_BUILDER_INIT;
662 GckSession *pkcs11_session = NULL;
663 DBusError derr = DBUS_ERROR_INIT;
664 GkdSecretSecret *secret = NULL;
665 dbus_bool_t replace = FALSE;
666 GckAttributes *attrs = NULL;
667 const GckAttribute *fields;
668 DBusMessageIter iter, array;
669 GckObject *item = NULL;
670 const gchar *prompt;
671 const gchar *base;
672 GError *error = NULL;
673 DBusMessage *reply = NULL;
674 gchar *path = NULL;
675 gchar *identifier;
676 gboolean created = FALSE;
677
678 /* Parse the message */
679 if (!dbus_message_has_signature (message, "a{sv}(oayays)b"))
680 return NULL;
681 if (!dbus_message_iter_init (message, &iter))
682 g_return_val_if_reached (NULL);
683 dbus_message_iter_recurse (&iter, &array);
684 if (!gkd_secret_property_parse_all (&array, SECRET_ITEM_INTERFACE, &builder)) {
685 reply = dbus_message_new_error (message, DBUS_ERROR_INVALID_ARGS,
686 "Invalid properties argument");
687 goto cleanup;
688 }
689 dbus_message_iter_next (&iter);
690 secret = gkd_secret_secret_parse (self->service, message, &iter, &derr);
691 if (secret == NULL) {
692 reply = gkd_secret_error_to_reply (message, &derr);
693 goto cleanup;
694 }
695 dbus_message_iter_next (&iter);
696 dbus_message_iter_get_basic (&iter, &replace);
697
698 base = dbus_message_get_path (message);
699 if (!parse_object_path (self, base, &identifier, NULL))
700 g_return_val_if_reached (NULL);
701 g_return_val_if_fail (identifier, NULL);
702
703 pkcs11_session = gck_object_get_session (object);
704 g_return_val_if_fail (pkcs11_session, NULL);
705
706 attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
707
708 if (replace) {
709 fields = gck_attributes_find (attrs, CKA_G_FIELDS);
710 if (fields)
711 item = collection_find_matching_item (self, pkcs11_session, identifier, fields);
712 }
713
714 /* Replace the item */
715 if (item) {
716 if (!gck_object_set (item, attrs, NULL, &error))
717 goto cleanup;
718
719 /* Create a new item */
720 } else {
721 gck_builder_add_all (&builder, attrs);
722 gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
723 gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
724 item = gck_session_create_object (pkcs11_session, gck_builder_end (&builder), NULL, &error);
725 if (item == NULL)
726 goto cleanup;
727 created = TRUE;
728 }
729
730 /* Set the secret */
731 if (!gkd_secret_session_set_item_secret (secret->session, item, secret, &derr)) {
732 if (created) /* If we created, then try to destroy on failure */
733 gck_object_destroy (item, NULL, NULL);
734 goto cleanup;
735 }
736
737 path = object_path_for_item (base, item);
738 gkd_secret_objects_emit_item_created (self, object, item);
739
740 /* Build up the item identifier */
741 reply = dbus_message_new_method_return (message);
742 dbus_message_iter_init_append (reply, &iter);
743 dbus_message_iter_append_basic (&iter, DBUS_TYPE_OBJECT_PATH, &path);
744 prompt = "/";
745 dbus_message_iter_append_basic (&iter, DBUS_TYPE_OBJECT_PATH, &prompt);
746
747cleanup:
748 if (error) {
749 if (!reply) {
750 if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
751 reply = dbus_message_new_error_printf (message, SECRET_ERROR_IS_LOCKED,
752 "Cannot create an item in a locked collection");
753 else
754 reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
755 "Couldn't create item: %s", egg_error_message (error));
756 }
757 g_clear_error (&error);
758 }
759
760 if (dbus_error_is_set (&derr)) {
761 if (!reply)
762 reply = dbus_message_new_error (message, derr.name, derr.message);
763 dbus_error_free (&derr);
764 }
765
766 gkd_secret_secret_free (secret);
767 gck_attributes_unref (attrs);
768 if (item)
769 g_object_unref (item);
770 if (pkcs11_session)
771 g_object_unref (pkcs11_session);
772 g_free (path);
773
774 return reply;
775}
776
777static DBusMessage*
778collection_method_delete (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
779{
780 GError *error = NULL;
781 DBusMessage *reply;
782 const gchar *prompt;
783 gchar *path;
784
785 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INVALID))
786 return NULL;
787
788 path = object_path_for_collection (object);
789 g_return_val_if_fail (path != NULL, NULL);
790
791 if (!gck_object_destroy (object, NULL, &error)) {
792 reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
793 "Couldn't delete collection: %s",
794 egg_error_message (error));
795 g_clear_error (&error);
796 g_free (path);
797 return reply;
798 }
799
800 /* Notify the callers that a collection was deleted */
801 gkd_secret_service_emit_collection_deleted (self->service, path);
802 g_free (path);
803
804 prompt = "/";
805 reply = dbus_message_new_method_return (message);
806 dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &prompt, DBUS_TYPE_INVALID);
807 return reply;
808}
809
810static void
811on_each_path_append_to_array (GkdSecretObjects *self,
812 const gchar *path,
813 GckObject *object,
814 gpointer user_data)
815{
816 GPtrArray *array = user_data;
817 g_ptr_array_add (array, g_strdup (path));
818}
819
820static DBusMessage *
821collection_introspect (GkdSecretObjects *self,
822 GckObject *object,
823 DBusMessage *message)
824{
825 GPtrArray *names;
826 DBusMessage *reply;
827
828 names = g_ptr_array_new_with_free_func (g_free);
829 gkd_secret_objects_foreach_item (self, message, dbus_message_get_path (message),
830 on_each_path_append_to_array, names);
831 g_ptr_array_add (names, NULL);
832
833 reply = gkd_dbus_introspect_handle (message, gkd_secret_introspect_collection,
834 (const gchar **)names->pdata);
835
836 g_ptr_array_unref (names);
837 return reply;
838}
839
840static DBusMessage*
841collection_message_handler (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
842{
843 /* org.freedesktop.Secret.Collection.Delete() */
844 if (dbus_message_is_method_call (message, SECRET_COLLECTION_INTERFACE, "Delete"))
845 return collection_method_delete (self, object, message);
846
847 /* org.freedesktop.Secret.Collection.SearchItems() */
848 if (dbus_message_is_method_call (message, SECRET_COLLECTION_INTERFACE, "SearchItems"))
849 return collection_method_search_items (self, object, message);
850
851 /* org.freedesktop.Secret.Collection.CreateItem() */
852 if (dbus_message_is_method_call (message, SECRET_COLLECTION_INTERFACE, "CreateItem"))
853 return collection_method_create_item (self, object, message);
854
855 /* org.freedesktop.DBus.Properties.Get() */
856 if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Get"))
857 return collection_property_get (self, object, message);
858
859 /* org.freedesktop.DBus.Properties.Set() */
860 else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Set"))
861 return collection_property_set (self, object, message);
862
863 /* org.freedesktop.DBus.Properties.GetAll() */
864 else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "GetAll"))
865 return collection_property_getall (self, object, message);
866
867 /* org.freedesktop.DBus.Introspectable.Introspect() */
868 else if (dbus_message_has_interface (message, DBUS_INTERFACE_INTROSPECTABLE))
869 return collection_introspect (self, object, message);
870
871 return NULL;
872}
873
874/* -----------------------------------------------------------------------------
875 * OBJECT
876 */
877
878static GObject*
879gkd_secret_objects_constructor (GType type, guint n_props, GObjectConstructParam *props)
880{
881 GkdSecretObjects *self = GKD_SECRET_OBJECTS (G_OBJECT_CLASS (gkd_secret_objects_parent_class)->constructor(type, n_props, props));
882
883 g_return_val_if_fail (self, NULL);
884 g_return_val_if_fail (self->pkcs11_slot, NULL);
885 g_return_val_if_fail (self->service, NULL);
886
887 return G_OBJECT (self);
888}
889
890static void
891gkd_secret_objects_init (GkdSecretObjects *self)
892{
893
894}
895
896static void
897gkd_secret_objects_dispose (GObject *obj)
898{
899 GkdSecretObjects *self = GKD_SECRET_OBJECTS (obj);
900
901 if (self->pkcs11_slot) {
902 g_object_unref (self->pkcs11_slot);
903 self->pkcs11_slot = NULL;
904 }
905
906 if (self->service) {
907 g_object_remove_weak_pointer (G_OBJECT (self->service),
908 (gpointer*)&(self->service));
909 self->service = NULL;
910 }
911
912 G_OBJECT_CLASS (gkd_secret_objects_parent_class)->dispose (obj);
913}
914
915static void
916gkd_secret_objects_finalize (GObject *obj)
917{
918 GkdSecretObjects *self = GKD_SECRET_OBJECTS (obj);
919
920 g_assert (!self->pkcs11_slot);
921 g_assert (!self->service);
922
923 G_OBJECT_CLASS (gkd_secret_objects_parent_class)->finalize (obj);
924}
925
926static void
927gkd_secret_objects_set_property (GObject *obj, guint prop_id, const GValue *value,
928 GParamSpec *pspec)
929{
930 GkdSecretObjects *self = GKD_SECRET_OBJECTS (obj);
931
932 switch (prop_id) {
933 case PROP_PKCS11_SLOT:
934 g_return_if_fail (!self->pkcs11_slot);
935 self->pkcs11_slot = g_value_dup_object (value);
936 g_return_if_fail (self->pkcs11_slot);
937 break;
938 case PROP_SERVICE:
939 g_return_if_fail (!self->service);
940 self->service = g_value_get_object (value);
941 g_return_if_fail (self->service);
942 g_object_add_weak_pointer (G_OBJECT (self->service),
943 (gpointer*)&(self->service));
944 break;
945 default:
946 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
947 break;
948 }
949}
950
951static void
952gkd_secret_objects_get_property (GObject *obj, guint prop_id, GValue *value,
953 GParamSpec *pspec)
954{
955 GkdSecretObjects *self = GKD_SECRET_OBJECTS (obj);
956
957 switch (prop_id) {
958 case PROP_PKCS11_SLOT:
959 g_value_set_object (value, gkd_secret_objects_get_pkcs11_slot (self));
960 break;
961 case PROP_SERVICE:
962 g_value_set_object (value, self->service);
963 break;
964 default:
965 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
966 break;
967 }
968}
969
970static void
971gkd_secret_objects_class_init (GkdSecretObjectsClass *klass)
972{
973 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
974
975 gobject_class->constructor = gkd_secret_objects_constructor;
976 gobject_class->dispose = gkd_secret_objects_dispose;
977 gobject_class->finalize = gkd_secret_objects_finalize;
978 gobject_class->set_property = gkd_secret_objects_set_property;
979 gobject_class->get_property = gkd_secret_objects_get_property;
980
981 g_object_class_install_property (gobject_class, PROP_PKCS11_SLOT,
982 g_param_spec_object ("pkcs11-slot", "Pkcs11 Slot", "PKCS#11 slot that we use for secrets",
983 GCK_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
984
985 g_object_class_install_property (gobject_class, PROP_SERVICE,
986 g_param_spec_object ("service", "Service", "Service which owns this objects",
987 GKD_SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
988}
989
990/* -----------------------------------------------------------------------------
991 * PUBLIC
992 */
993
994GckSlot*
995gkd_secret_objects_get_pkcs11_slot (GkdSecretObjects *self)
996{
997 g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
998 return self->pkcs11_slot;
999}
1000
1001DBusMessage*
1002gkd_secret_objects_dispatch (GkdSecretObjects *self, DBusMessage *message)
1003{
1004 GckBuilder builder = GCK_BUILDER_INIT;
1005 DBusMessage *reply = NULL;
1006 GError *error = NULL;
1007 GList *objects;
1008 GckSession *session;
1009 gchar *c_ident;
1010 gchar *i_ident;
1011 gboolean is_item;
1012 const char *path;
1013
1014 g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1015 g_return_val_if_fail (message, NULL);
1016
1017 path = dbus_message_get_path (message);
1018 g_return_val_if_fail (path, NULL);
1019
1020 if (!parse_object_path (self, path, &c_ident, &i_ident) || !c_ident)
1021 return gkd_secret_error_no_such_object (message);
1022
1023 /* The session we're using to access the object */
1024 session = gkd_secret_service_get_pkcs11_session (self->service, dbus_message_get_sender (message));
1025 g_return_val_if_fail (session, NULL);
1026
1027 if (i_ident) {
1028 is_item = TRUE;
1029 gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
1030 gck_builder_add_string (&builder, CKA_G_COLLECTION, c_ident);
1031 gck_builder_add_string (&builder, CKA_ID, i_ident);
1032 } else {
1033 is_item = FALSE;
1034 gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
1035 gck_builder_add_string (&builder, CKA_ID, c_ident);
1036 }
1037
1038 objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1039
1040 g_free (c_ident);
1041 g_free (i_ident);
1042
1043 if (error != NULL) {
1044 g_warning ("couldn't lookup object: %s: %s", path, egg_error_message (error));
1045 g_clear_error (&error);
1046 }
1047
1048 if (!objects)
1049 return gkd_secret_error_no_such_object (message);
1050
1051 if (is_item)
1052 reply = item_message_handler (self, objects->data, message);
1053 else
1054 reply = collection_message_handler (self, objects->data, message);
1055
1056 gck_list_unref_free (objects);
1057 return reply;
1058}
1059
1060GckObject*
1061gkd_secret_objects_lookup_collection (GkdSecretObjects *self, const gchar *caller,
1062 const gchar *path)
1063{
1064 GckBuilder builder = GCK_BUILDER_INIT;
1065 GckObject *object = NULL;
1066 GError *error = NULL;
1067 GList *objects;
1068 GckSession *session;
1069 gchar *identifier;
1070
1071 g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1072 g_return_val_if_fail (path, NULL);
1073
1074 if (!parse_object_path (self, path, &identifier, NULL))
1075 return NULL;
1076
1077 /* The session we're using to access the object */
1078 if (caller == NULL)
1079 session = gkd_secret_service_internal_pkcs11_session (self->service);
1080 else
1081 session = gkd_secret_service_get_pkcs11_session (self->service, caller);
1082 g_return_val_if_fail (session, NULL);
1083
1084 gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
1085 gck_builder_add_string (&builder, CKA_ID, identifier);
1086
1087 objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1088
1089 g_free (identifier);
1090
1091 if (error != NULL) {
1092 g_warning ("couldn't lookup collection: %s: %s", path, egg_error_message (error));
1093 g_clear_error (&error);
1094 }
1095
1096 if (objects)
1097 object = g_object_ref (objects->data);
1098
1099 gck_list_unref_free (objects);
1100 return object;
1101}
1102
1103GckObject*
1104gkd_secret_objects_lookup_item (GkdSecretObjects *self, const gchar *caller,
1105 const gchar *path)
1106{
1107 GckBuilder builder = GCK_BUILDER_INIT;
1108 GckObject *object = NULL;
1109 GError *error = NULL;
1110 GList *objects;
1111 GckSession *session;
1112 gchar *collection;
1113 gchar *identifier;
1114
1115 g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1116 g_return_val_if_fail (caller, NULL);
1117 g_return_val_if_fail (path, NULL);
1118
1119 if (!parse_object_path (self, path, &collection, &identifier))
1120 return NULL;
1121
1122 /* The session we're using to access the object */
1123 session = gkd_secret_service_get_pkcs11_session (self->service, caller);
1124 g_return_val_if_fail (session, NULL);
1125
1126 gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
1127 gck_builder_add_string (&builder, CKA_ID, identifier);
1128 gck_builder_add_string (&builder, CKA_G_COLLECTION, collection);
1129
1130 objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1131
1132 g_free (identifier);
1133 g_free (collection);
1134
1135 if (error != NULL) {
1136 g_warning ("couldn't lookup item: %s: %s", path, egg_error_message (error));
1137 g_clear_error (&error);
1138 }
1139
1140 if (objects)
1141 object = g_object_ref (objects->data);
1142
1143 gck_list_unref_free (objects);
1144 return object;
1145}
1146
1147static void
1148objects_foreach_item (GkdSecretObjects *self,
1149 GList *items,
1150 const gchar *base,
1151 GkdSecretObjectsForeach callback,
1152 gpointer user_data)
1153{
1154 gchar *path;
1155 GList *l;
1156
1157 for (l = items; l; l = g_list_next (l)) {
1158 path = object_path_for_item (base, l->data);
1159 (callback) (self, path, l->data, user_data);
1160 g_free (path);
1161 }
1162}
1163
1164void
1165gkd_secret_objects_foreach_item (GkdSecretObjects *self,
1166 DBusMessage *message,
1167 const gchar *base,
1168 GkdSecretObjectsForeach callback,
1169 gpointer user_data)
1170{
1171 GckBuilder builder = GCK_BUILDER_INIT;
1172 GckSession *session;
1173 GError *error = NULL;
1174 gchar *identifier;
1175 GList *items;
1176
1177 g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1178 g_return_if_fail (base != NULL);
1179 g_return_if_fail (callback != NULL);
1180
1181 /* The session we're using to access the object */
1182 if (message == NULL) {
1183 session = gkd_secret_service_internal_pkcs11_session (self->service);
1184 } else {
1185 session = gkd_secret_service_get_pkcs11_session (self->service,
1186 dbus_message_get_sender (message));
1187 }
1188
1189 if (!parse_object_path (self, base, &identifier, NULL))
1190 g_return_if_reached ();
1191
1192 gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
1193 gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
1194
1195 items = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1196
1197 if (error == NULL) {
1198 objects_foreach_item (self, items, base, callback, user_data);
1199
1200 } else {
1201 g_warning ("couldn't lookup items in '%s' collection: %s", identifier, egg_error_message (error));
1202 g_clear_error (&error);
1203 }
1204
1205 gck_list_unref_free (items);
1206 g_free (identifier);
1207}
1208
1209static void
1210on_object_path_append_to_iter (GkdSecretObjects *self,
1211 const gchar *path,
1212 GckObject *object,
1213 gpointer user_data)
1214{
1215 DBusMessageIter *array = user_data;
1216 dbus_message_iter_append_basic (array, DBUS_TYPE_OBJECT_PATH, &path);
1217}
1218
1219void
1220gkd_secret_objects_append_item_paths (GkdSecretObjects *self,
1221 const gchar *base,
1222 DBusMessageIter *iter,
1223 DBusMessage *message)
1224{
1225 DBusMessageIter variant;
1226 DBusMessageIter array;
1227
1228 g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1229 g_return_if_fail (base);
1230 g_return_if_fail (iter);
1231
1232
1233 dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "ao", &variant);
1234 dbus_message_iter_open_container (&variant, DBUS_TYPE_ARRAY, "o", &array);
1235
1236 gkd_secret_objects_foreach_item (self, message, base, on_object_path_append_to_iter, &array);
1237
1238 dbus_message_iter_close_container (&variant, &array);
1239 dbus_message_iter_close_container (iter, &variant);
1240}
1241
1242void
1243gkd_secret_objects_foreach_collection (GkdSecretObjects *self,
1244 DBusMessage *message,
1245 GkdSecretObjectsForeach callback,
1246 gpointer user_data)
1247{
1248 GckBuilder builder = GCK_BUILDER_INIT;
1249 GckSession *session;
1250 GError *error = NULL;
1251 GList *collections, *l;
1252 gpointer identifier;
1253 gsize n_identifier;
1254 gchar *path;
1255
1256 g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1257 g_return_if_fail (callback);
1258
1259 /* The session we're using to access the object */
1260 if (message == NULL) {
1261 session = gkd_secret_service_internal_pkcs11_session (self->service);
1262 } else {
1263 session = gkd_secret_service_get_pkcs11_session (self->service,
1264 dbus_message_get_sender (message));
1265 }
1266
1267 gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
1268
1269 collections = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
1270
1271 if (error != NULL) {
1272 g_warning ("couldn't lookup collections: %s", egg_error_message (error));
1273 g_clear_error (&error);
1274 return;
1275 }
1276
1277 for (l = collections; l; l = g_list_next (l)) {
1278
1279 identifier = gck_object_get_data (l->data, CKA_ID, NULL, &n_identifier, &error);
1280 if (identifier == NULL) {
1281 g_warning ("couldn't get collection identifier: %s", egg_error_message (error));
1282 g_clear_error (&error);
1283 continue;
1284 }
1285
1286 path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
1287 g_free (identifier);
1288
1289 (callback) (self, path, l->data, user_data);
1290 g_free (path);
1291 }
1292
1293 gck_list_unref_free (collections);
1294}
1295
1296void
1297gkd_secret_objects_append_collection_paths (GkdSecretObjects *self,
1298 DBusMessageIter *iter,
1299 DBusMessage *message)
1300{
1301 DBusMessageIter variant;
1302 DBusMessageIter array;
1303
1304 g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1305 g_return_if_fail (iter != NULL);
1306
1307 dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "ao", &variant);
1308 dbus_message_iter_open_container (&variant, DBUS_TYPE_ARRAY, "o", &array);
1309
1310 gkd_secret_objects_foreach_collection (self, message, on_object_path_append_to_iter, &array);
1311
1312 dbus_message_iter_close_container (&variant, &array);
1313 dbus_message_iter_close_container (iter, &variant);
1314}
1315
1316DBusMessage*
1317gkd_secret_objects_handle_search_items (GkdSecretObjects *self, DBusMessage *message,
1318 const gchar *base)
1319{
1320 GckBuilder builder = GCK_BUILDER_INIT;
1321 DBusMessageIter iter;
1322 DBusMessageIter array;
1323 GckObject *search;
1324 GckSession *session;
1325 DBusMessage *reply;
1326 GError *error = NULL;
1327 gchar *identifier;
1328 gpointer data;
1329 gsize n_data;
1330 GList *locked, *unlocked;
1331 GList *items;
1332
1333 g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
1334 g_return_val_if_fail (message, NULL);
1335
1336 if (!dbus_message_has_signature (message, "a{ss}"))
1337 return NULL;
1338
1339 dbus_message_iter_init (message, &iter);
1340 if (!gkd_secret_property_parse_fields (&iter, &builder)) {
1341 gck_builder_clear (&builder);
1342 return dbus_message_new_error (message, DBUS_ERROR_FAILED,
1343 "Invalid data in attributes argument");
1344 }
1345
1346 if (base != NULL) {
1347 if (!parse_object_path (self, base, &identifier, NULL))
1348 g_return_val_if_reached (NULL);
1349 gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier);
1350 g_free (identifier);
1351 }
1352
1353 gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_SEARCH);
1354 gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);
1355
1356 /* The session we're using to access the object */
1357 session = gkd_secret_service_get_pkcs11_session (self->service, dbus_message_get_sender (message));
1358 g_return_val_if_fail (session, NULL);
1359
1360 /* Create the search object */
1361 search = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error);
1362
1363 if (error != NULL) {
1364 reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
1365 "Couldn't search for items: %s",
1366 egg_error_message (error));
1367 g_clear_error (&error);
1368 return reply;
1369 }
1370
1371 /* Get the matched item handles, and delete the search object */
1372 data = gck_object_get_data (search, CKA_G_MATCHED, NULL, &n_data, &error);
1373 gck_object_destroy (search, NULL, NULL);
1374 g_object_unref (search);
1375
1376 if (error != NULL) {
1377 reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
1378 "Couldn't retrieve matched items: %s",
1379 egg_error_message (error));
1380 g_clear_error (&error);
1381 return reply;
1382 }
1383
1384 /* Build a list of object handles */
1385 items = gck_objects_from_handle_array (session, data, n_data / sizeof (CK_OBJECT_HANDLE));
1386 g_free (data);
1387
1388 /* Filter out the locked items */
1389 item_cleanup_search_results (session, items, &locked, &unlocked);
1390
1391 /* Prepare the reply message */
1392 reply = dbus_message_new_method_return (message);
1393 dbus_message_iter_init_append (reply, &iter);
1394
1395 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
1396 objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_iter, &array);
1397 dbus_message_iter_close_container (&iter, &array);
1398
1399 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
1400 objects_foreach_item (self, locked, NULL, on_object_path_append_to_iter, &array);
1401 dbus_message_iter_close_container (&iter, &array);
1402
1403 g_list_free (locked);
1404 g_list_free (unlocked);
1405 gck_list_unref_free (items);
1406
1407 return reply;
1408}
1409
1410DBusMessage*
1411gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self, DBusMessage *message)
1412{
1413 DBusError derr = DBUS_ERROR_INIT;
1414 GkdSecretSession *session;
1415 GkdSecretSecret *secret;
1416 DBusMessage *reply;
1417 GckObject *item;
1418 DBusMessageIter iter, array, dict;
1419 const char *session_path;
1420 const char *caller;
1421 char **paths;
1422 int n_paths, i;
1423
1424 if (!dbus_message_get_args (message, NULL,
1425 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &paths, &n_paths,
1426 DBUS_TYPE_OBJECT_PATH, &session_path,
1427 DBUS_TYPE_INVALID))
1428 return NULL;
1429
1430 caller = dbus_message_get_sender (message);
1431 g_return_val_if_fail (caller, NULL);
1432
1433 session = gkd_secret_service_lookup_session (self->service, session_path,
1434 dbus_message_get_sender (message));
1435 if (session == NULL)
1436 return dbus_message_new_error (message, SECRET_ERROR_NO_SESSION, "The session does not exist");
1437
1438 reply = dbus_message_new_method_return (message);
1439 dbus_message_iter_init_append (reply, &iter);
1440 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{o(oayays)}", &array);
1441
1442 for (i = 0; i < n_paths; ++i) {
1443
1444 /* Try to find the item, if it doesn't exist, just ignore */
1445 item = gkd_secret_objects_lookup_item (self, caller, paths[i]);
1446 if (!item)
1447 continue;
1448
1449 secret = gkd_secret_session_get_item_secret (session, item, &derr);
1450 g_object_unref (item);
1451
1452 if (secret == NULL) {
1453 /* We ignore is locked, and just leave out from response */
1454 if (dbus_error_has_name (&derr, SECRET_ERROR_IS_LOCKED)) {
1455 dbus_error_free (&derr);
1456 continue;
1457
1458 /* All other errors stop the operation */
1459 } else {
1460 dbus_message_unref (reply);
1461 reply = dbus_message_new_error (message, derr.name, derr.message);
1462 dbus_error_free (&derr);
1463 break;
1464 }
1465 }
1466
1467 dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
1468 dbus_message_iter_append_basic (&dict, DBUS_TYPE_OBJECT_PATH, &(paths[i]));
1469 gkd_secret_secret_append (secret, &dict);
1470 gkd_secret_secret_free (secret);
1471 dbus_message_iter_close_container (&array, &dict);
1472 }
1473
1474 if (i == n_paths)
1475 dbus_message_iter_close_container (&iter, &array);
1476 dbus_free_string_array (paths);
1477
1478 return reply;
1479}
1480
1481static void
1482on_each_item_emit_locked (GkdSecretObjects *self,
1483 const gchar *path,
1484 GckObject *object,
1485 gpointer user_data)
1486{
1487 gkd_secret_objects_emit_item_changed (self, object, "Locked", NULL);
1488}
1489
1490void
1491gkd_secret_objects_emit_collection_locked (GkdSecretObjects *self,
1492 GckObject *collection)
1493{
1494 const gchar *collection_path;
1495
1496 collection_path = object_path_for_collection (collection);
1497 gkd_secret_objects_foreach_item (self, NULL, collection_path,
1498 on_each_item_emit_locked, NULL);
1499
1500 gkd_secret_objects_emit_collection_changed (self, collection, "Locked", NULL);
1501}
1502
1503static void
1504emit_object_properties_changed (GkdSecretObjects *self,
1505 GckObject *object,
1506 const gchar *path,
1507 const gchar *iface,
1508 va_list va)
1509{
1510 gchar *collection_path;
1511 const gchar *propname;
1512 DBusMessage *message;
1513 DBusMessageIter iter;
1514 DBusMessageIter array;
1515 DBusMessageIter dict;
1516 CK_ATTRIBUTE_TYPE type;
1517 GckAttributes *attrs;
1518 GError *error = NULL;
1519 gboolean items = FALSE;
1520 GArray *types;
1521
1522 types = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE_TYPE));
1523 while ((propname = va_arg (va, const gchar *)) != NULL) {
1524
1525 /* Special case the Items property */
1526 if (g_str_equal (propname, "Items")) {
1527 items = TRUE;
1528 continue;
1529 }
1530
1531 if (gkd_secret_property_get_type (propname, &type))
1532 g_array_append_val (types, type);
1533 else
1534 g_warning ("invalid property: %s", propname);
1535 }
1536
1537 attrs = gck_object_get_full (object, (CK_ATTRIBUTE_TYPE *)types->data,
1538 types->len, NULL, &error);
1539 g_array_free (types, TRUE);
1540
1541 if (error != NULL) {
1542 g_warning ("couldn't retrieve properties: %s", egg_error_message (error));
1543 return;
1544 }
1545
1546 message = dbus_message_new_signal (path, DBUS_INTERFACE_PROPERTIES,
1547 "PropertiesChanged");
1548
1549 dbus_message_iter_init_append (message, &iter);
1550 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &iface);
1551 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
1552 gkd_secret_property_append_all (&array, attrs);
1553
1554 /* Append the Items property */
1555 if (items) {
1556 collection_path = object_path_for_collection (object);
1557 dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
1558 propname = "Items";
1559 dbus_message_iter_append_basic (&dict, DBUS_TYPE_STRING, &propname);
1560 gkd_secret_objects_append_item_paths (self, collection_path, &dict, NULL);
1561 dbus_message_iter_close_container (&array, &dict);
1562 g_free (collection_path);
1563 }
1564
1565 dbus_message_iter_close_container (&iter, &array);
1566 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &array);
1567 dbus_message_iter_close_container (&iter, &array);
1568
1569 if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
1570 message, NULL))
1571 g_return_if_reached ();
1572 dbus_message_unref (message);
1573
1574 gck_attributes_unref (attrs);
1575}
1576
1577void
1578gkd_secret_objects_emit_collection_changed (GkdSecretObjects *self,
1579 GckObject *collection,
1580 ...)
1581{
1582 DBusMessage *message;
1583 gchar *collection_path;
1584 va_list va;
1585
1586 g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1587 g_return_if_fail (GCK_OBJECT (collection));
1588
1589 collection_path = object_path_for_collection (collection);
1590
1591 message = dbus_message_new_signal (SECRET_SERVICE_PATH,
1592 SECRET_SERVICE_INTERFACE,
1593 "CollectionChanged");
1594 dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &collection_path,
1595 DBUS_TYPE_INVALID);
1596
1597 if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
1598 message, NULL))
1599 g_return_if_reached ();
1600
1601 dbus_message_unref (message);
1602
1603 va_start (va, collection);
1604 emit_object_properties_changed (self, collection, collection_path,
1605 SECRET_COLLECTION_INTERFACE, va);
1606 va_end (va);
1607
1608 g_free (collection_path);
1609}
1610
1611void
1612gkd_secret_objects_emit_item_created (GkdSecretObjects *self,
1613 GckObject *collection,
1614 GckObject *item)
1615{
1616 DBusMessage *message;
1617 gchar *collection_path;
1618 gchar *item_path;
1619
1620 g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1621 g_return_if_fail (GCK_OBJECT (collection));
1622 g_return_if_fail (GCK_OBJECT (item));
1623
1624 collection_path = object_path_for_collection (collection);
1625 item_path = object_path_for_item (collection_path, item);
1626
1627 message = dbus_message_new_signal (collection_path,
1628 SECRET_COLLECTION_INTERFACE,
1629 "ItemCreated");
1630 dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &item_path,
1631 DBUS_TYPE_INVALID);
1632
1633 if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
1634 message, NULL))
1635 g_return_if_reached ();
1636
1637 dbus_message_unref (message);
1638
1639 gkd_secret_objects_emit_collection_changed (self, collection, "Items", NULL);
1640
1641 g_free (item_path);
1642 g_free (collection_path);
1643}
1644
1645void
1646gkd_secret_objects_emit_item_changed (GkdSecretObjects *self,
1647 GckObject *item,
1648 ...)
1649{
1650 DBusMessage *message;
1651 gchar *collection_path;
1652 gchar *item_path;
1653 va_list va;
1654
1655 g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1656 g_return_if_fail (GCK_OBJECT (item));
1657
1658 collection_path = collection_path_for_item (item);
1659 item_path = object_path_for_item (collection_path, item);
1660
1661 message = dbus_message_new_signal (collection_path,
1662 SECRET_COLLECTION_INTERFACE,
1663 "ItemChanged");
1664 dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &item_path,
1665 DBUS_TYPE_INVALID);
1666
1667 if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
1668 message, NULL))
1669 g_return_if_reached ();
1670
1671 dbus_message_unref (message);
1672
1673 va_start (va, item);
1674 emit_object_properties_changed (self, item, item_path,
1675 SECRET_ITEM_INTERFACE, va);
1676 va_end (va);
1677
1678 g_free (item_path);
1679 g_free (collection_path);
1680}
1681
1682void
1683gkd_secret_objects_emit_item_deleted (GkdSecretObjects *self,
1684 GckObject *collection,
1685 const gchar *item_path)
1686{
1687 DBusMessage *message;
1688 gchar *collection_path;
1689
1690 g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
1691 g_return_if_fail (GCK_OBJECT (collection));
1692 g_return_if_fail (item_path != NULL);
1693
1694 collection_path = object_path_for_collection (collection);
1695
1696 message = dbus_message_new_signal (collection_path,
1697 SECRET_COLLECTION_INTERFACE,
1698 "ItemDeleted");
1699 dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &item_path,
1700 DBUS_TYPE_INVALID);
1701
1702 if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
1703 message, NULL))
1704 g_return_if_reached ();
1705
1706 dbus_message_unref (message);
1707 g_free (collection_path);
1708
1709 gkd_secret_objects_emit_collection_changed (self, collection, "Items", NULL);
1710}
01711
=== added file '.pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.h'
--- .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.h 1970-01-01 00:00:00 +0000
+++ .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-objects.h 2013-03-14 13:26:21 +0000
@@ -0,0 +1,112 @@
1/*
2 * gnome-keyring
3 *
4 * Copyright (C) 2009 Stefan Walter
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#ifndef __GKD_SECRET_OBJECTS_H__
23#define __GKD_SECRET_OBJECTS_H__
24
25#include "gkd-secret-types.h"
26
27#include <gck/gck.h>
28
29#include <glib-object.h>
30
31#include <dbus/dbus.h>
32
33#define GKD_SECRET_TYPE_OBJECTS (gkd_secret_objects_get_type ())
34#define GKD_SECRET_OBJECTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKD_SECRET_TYPE_OBJECTS, GkdSecretObjects))
35#define GKD_SECRET_OBJECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GKD_SECRET_TYPE_OBJECTS, GkdSecretObjectsClass))
36#define GKD_SECRET_IS_OBJECTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKD_SECRET_TYPE_OBJECTS))
37#define GKD_SECRET_IS_OBJECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GKD_SECRET_TYPE_OBJECTS))
38#define GKD_SECRET_OBJECTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKD_SECRET_TYPE_OBJECTS, GkdSecretObjectsClass))
39
40typedef struct _GkdSecretObjectsClass GkdSecretObjectsClass;
41
42struct _GkdSecretObjectsClass {
43 GObjectClass parent_class;
44};
45
46typedef void (*GkdSecretObjectsForeach) (GkdSecretObjects *self,
47 const gchar *path,
48 GckObject *object,
49 gpointer user_data);
50
51GType gkd_secret_objects_get_type (void);
52
53DBusMessage* gkd_secret_objects_dispatch (GkdSecretObjects *self,
54 DBusMessage *message);
55
56DBusMessage* gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
57 DBusMessage *message,
58 const gchar *base);
59
60DBusMessage* gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self,
61 DBusMessage *message);
62
63void gkd_secret_objects_foreach_collection (GkdSecretObjects *self,
64 DBusMessage *message,
65 GkdSecretObjectsForeach callback,
66 gpointer user_data);
67
68void gkd_secret_objects_foreach_item (GkdSecretObjects *self,
69 DBusMessage *message,
70 const gchar *base,
71 GkdSecretObjectsForeach callback,
72 gpointer user_data);
73
74void gkd_secret_objects_append_collection_paths (GkdSecretObjects *self,
75 DBusMessageIter *iter,
76 DBusMessage *message);
77
78void gkd_secret_objects_append_item_paths (GkdSecretObjects *self,
79 const gchar *base,
80 DBusMessageIter *iter,
81 DBusMessage *message);
82
83GckSlot* gkd_secret_objects_get_pkcs11_slot (GkdSecretObjects *self);
84
85GckObject* gkd_secret_objects_lookup_collection (GkdSecretObjects *self,
86 const gchar *caller,
87 const gchar *path);
88
89GckObject* gkd_secret_objects_lookup_item (GkdSecretObjects *self,
90 const gchar *caller,
91 const gchar *path);
92
93void gkd_secret_objects_emit_collection_locked (GkdSecretObjects *self,
94 GckObject *collection);
95
96void gkd_secret_objects_emit_collection_changed (GkdSecretObjects *self,
97 GckObject *collection,
98 ...) G_GNUC_NULL_TERMINATED;
99
100void gkd_secret_objects_emit_item_created (GkdSecretObjects *self,
101 GckObject *collection,
102 GckObject *item);
103
104void gkd_secret_objects_emit_item_changed (GkdSecretObjects *self,
105 GckObject *item,
106 ...) G_GNUC_NULL_TERMINATED;
107
108void gkd_secret_objects_emit_item_deleted (GkdSecretObjects *self,
109 GckObject *collection,
110 const gchar *item_path);
111
112#endif /* __GKD_SECRET_OBJECTS_H__ */
0113
=== added file '.pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-service.c'
--- .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-service.c 1970-01-01 00:00:00 +0000
+++ .pc/00git_fix_searchitems_method.patch/daemon/dbus/gkd-secret-service.c 2013-03-14 13:26:21 +0000
@@ -0,0 +1,1598 @@
1/*
2 * gnome-keyring
3 *
4 * Copyright (C) 2008 Stefan Walter
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include "config.h"
23
24#include "gkd-dbus-util.h"
25#include "gkd-secret-change.h"
26#include "gkd-secret-create.h"
27#include "gkd-secret-dispatch.h"
28#include "gkd-secret-error.h"
29#include "gkd-secret-introspect.h"
30#include "gkd-secret-lock.h"
31#include "gkd-secret-objects.h"
32#include "gkd-secret-prompt.h"
33#include "gkd-secret-property.h"
34#include "gkd-secret-secret.h"
35#include "gkd-secret-service.h"
36#include "gkd-secret-session.h"
37#include "gkd-secret-types.h"
38#include "gkd-secret-unlock.h"
39#include "gkd-secret-util.h"
40
41#include "egg/egg-error.h"
42#include "egg/egg-unix-credentials.h"
43
44#include <gck/gck.h>
45
46#include "pkcs11/pkcs11i.h"
47
48#include <string.h>
49
50enum {
51 PROP_0,
52 PROP_CONNECTION,
53 PROP_PKCS11_SLOT,
54};
55
56struct _GkdSecretService {
57 GObject parent;
58 DBusConnection *connection;
59 GHashTable *clients;
60 gchar *match_rule;
61 GkdSecretObjects *objects;
62 GHashTable *aliases;
63 GckSession *internal_session;
64 gchar *alias_directory;
65};
66
67typedef struct _ServiceClient {
68 gchar *caller_peer;
69 gchar *caller_exec;
70 pid_t caller_pid;
71 CK_G_APPLICATION app;
72 GckSession *pkcs11_session;
73 GHashTable *dispatch;
74} ServiceClient;
75
76/* Forward declaration */
77static void service_dispatch_message (GkdSecretService *, DBusMessage *);
78
79G_DEFINE_TYPE (GkdSecretService, gkd_secret_service, G_TYPE_OBJECT);
80
81/* -----------------------------------------------------------------------------
82 * INTERNAL
83 */
84
85static gchar*
86default_path (GkdSecretService *self)
87{
88 gchar *old_directory;
89 gchar *new_directory;
90
91 if (self->alias_directory == NULL) {
92 new_directory = g_build_filename (g_get_user_data_dir (), "keyrings", NULL);
93 old_directory = g_build_filename (g_get_home_dir (), ".gnome2", "keyrings", NULL);
94
95 if (!g_file_test (new_directory, G_FILE_TEST_IS_DIR) &&
96 g_file_test (old_directory, G_FILE_TEST_IS_DIR)) {
97 self->alias_directory = old_directory;
98 old_directory = NULL;
99 } else {
100 self->alias_directory = new_directory;
101 new_directory = NULL;
102 }
103
104 g_free (old_directory);
105 g_free (new_directory);
106 g_debug ("keyring alias directory: %s", self->alias_directory);
107 }
108
109 return g_build_filename (self->alias_directory, "default", NULL);
110}
111
112static void
113update_default (GkdSecretService *self, gboolean force)
114{
115 gchar *contents = NULL;
116 const gchar *identifier;
117 gchar *path;
118
119 if (!force) {
120 identifier = g_hash_table_lookup (self->aliases, "default");
121 if (identifier)
122 return;
123 }
124
125 path = default_path (self);
126 if (g_file_get_contents (path, &contents, NULL, NULL)) {
127 g_strstrip (contents);
128 if (!contents[0]) {
129 g_free (contents);
130 contents = NULL;
131 }
132 }
133 g_free (path);
134
135 g_hash_table_replace (self->aliases, g_strdup ("default"), contents);
136}
137
138static void
139store_default (GkdSecretService *self)
140{
141 GError *error = NULL;
142 const gchar *identifier;
143 gchar *path;
144
145 identifier = g_hash_table_lookup (self->aliases, "default");
146 if (!identifier)
147 return;
148
149 path = default_path (self);
150 if (!g_file_set_contents (path, identifier, -1, &error))
151 g_message ("couldn't store default keyring: %s", egg_error_message (error));
152 g_free (path);
153}
154
155static gboolean
156object_path_has_prefix (const gchar *path, const gchar *prefix)
157{
158 gsize len;
159
160 g_assert (prefix);
161
162 if (!path)
163 return FALSE;
164
165 len = strlen (prefix);
166 return g_ascii_strncasecmp (path, prefix, len) == 0 &&
167 (path[len] == '\0' || path[len] == '/');
168}
169
170static void
171dispose_and_unref (gpointer object)
172{
173 g_return_if_fail (G_IS_OBJECT (object));
174 g_object_run_dispose (G_OBJECT (object));
175 g_object_unref (object);
176}
177
178static void
179free_client (gpointer data)
180{
181 ServiceClient *client = data;
182
183 if (!client)
184 return;
185
186 /* Info about our client */
187 g_free (client->caller_peer);
188 g_free (client->caller_exec);
189
190 /* The session we use for accessing as our client */
191 if (client->pkcs11_session) {
192#if 0
193 gck_session_close (client->pkcs11_session, NULL);
194#endif
195 g_object_unref (client->pkcs11_session);
196 }
197
198 /* The sessions and prompts the client has open */
199 g_hash_table_destroy (client->dispatch);
200
201 g_free (client);
202}
203
204typedef struct _on_get_connection_unix_process_id_args {
205 GkdSecretService *self;
206 DBusMessage *message;
207} on_get_connection_unix_process_id_args;
208
209static void
210free_on_get_connection_unix_process_id_args (gpointer data)
211{
212 on_get_connection_unix_process_id_args *args = data;
213 if (args != NULL) {
214 g_object_unref (args->self);
215 dbus_message_unref (args->message);
216 g_free (args);
217 }
218}
219
220static void
221on_get_connection_unix_process_id (DBusPendingCall *pending, gpointer user_data)
222{
223 on_get_connection_unix_process_id_args *args = user_data;
224 DBusMessage *reply = NULL;
225 DBusError error = DBUS_ERROR_INIT;
226 dbus_uint32_t caller_pid = 0;
227 GkdSecretService *self;
228 ServiceClient *client;
229 const gchar *caller;
230
231 g_return_if_fail (GKD_SECRET_IS_SERVICE (args->self));
232 self = args->self;
233
234 /* Get the resulting process ID */
235 reply = dbus_pending_call_steal_reply (pending);
236 g_return_if_fail (reply);
237
238 caller = dbus_message_get_sender (args->message);
239 g_return_if_fail (caller);
240
241 client = g_hash_table_lookup (self->clients, caller);
242 if (client == NULL) {
243
244 /* An error returned from GetConnectionUnixProcessID */
245 if (dbus_set_error_from_message (&error, reply)) {
246 g_message ("couldn't get the caller's unix process id: %s", error.message);
247 caller_pid = 0;
248 dbus_error_free (&error);
249
250 /* A PID was returned from GetConnectionUnixProcessID */
251 } else {
252 if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &caller_pid, DBUS_TYPE_INVALID))
253 g_return_if_reached ();
254 }
255
256 /* Initialize the client object */
257 client = g_new0 (ServiceClient, 1);
258 client->caller_peer = g_strdup (caller);
259 client->caller_pid = caller_pid;
260 if (caller_pid != 0)
261 client->caller_exec = egg_unix_credentials_executable (caller_pid);
262 client->app.applicationData = client;
263 client->dispatch = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, dispose_and_unref);
264
265 g_hash_table_replace (self->clients, client->caller_peer, client);
266
267 /* Update default collection each time someone connects */
268 update_default (self, TRUE);
269 }
270
271 dbus_message_unref (reply);
272
273 /* Dispatch the original message again */
274 service_dispatch_message (self, args->message);
275}
276
277static void
278initialize_service_client (GkdSecretService *self, DBusMessage *message)
279{
280 on_get_connection_unix_process_id_args *args;
281 DBusMessage *request;
282 DBusPendingCall *pending;
283 const gchar *caller;
284
285 g_assert (GKD_SECRET_IS_SERVICE (self));
286 g_assert (message);
287
288 args = g_new0 (on_get_connection_unix_process_id_args, 1);
289 args->self = g_object_ref (self);
290 args->message = dbus_message_ref (message);
291
292 caller = dbus_message_get_sender (message);
293 g_return_if_fail (caller);
294
295 /* Message org.freedesktop.DBus.GetConnectionUnixProcessID(IN String caller) */
296 request = dbus_message_new_method_call ("org.freedesktop.DBus", "/org/freedesktop/DBus",
297 "org.freedesktop.DBus", "GetConnectionUnixProcessID");
298 if (!request || !dbus_message_append_args (request, DBUS_TYPE_STRING, &caller, DBUS_TYPE_INVALID))
299 g_return_if_reached ();
300
301 /*
302 * Send of request for GetConnectionUnixProcessID, with lowish timeout.
303 * We're only talking to the session bus, so the reply should be fast.
304 * In addition we want to send off a reply to our caller, before it
305 * times out.
306 */
307 if (!dbus_connection_send_with_reply (self->connection, request, &pending, 2000))
308 g_return_if_reached ();
309 dbus_message_unref (request);
310
311 /* Track our new session object, on this call */
312 dbus_pending_call_set_notify (pending, on_get_connection_unix_process_id, args,
313 free_on_get_connection_unix_process_id_args);
314 dbus_pending_call_unref (pending);
315}
316
317/* -----------------------------------------------------------------------------
318 * DBUS
319 */
320
321static DBusMessage*
322service_property_get (GkdSecretService *self, DBusMessage *message)
323{
324 DBusMessage *reply = NULL;
325 DBusMessageIter iter;
326 const gchar *interface;
327 const gchar *name;
328
329 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface,
330 DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
331 return NULL;
332
333 if (!gkd_dbus_interface_match (SECRET_SERVICE_INTERFACE, interface))
334 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
335 "Object does not have properties on interface '%s'",
336 interface);
337
338 /* The "Collections" property */
339 if (g_str_equal (name, "Collections")) {
340 reply = dbus_message_new_method_return (message);
341 dbus_message_iter_init_append (reply, &iter);
342 gkd_secret_objects_append_collection_paths (self->objects, &iter, message);
343
344 /* No such property */
345 } else {
346 reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
347 "Object does not have the '%s' property", name);
348 }
349
350 return reply;
351}
352
353static DBusMessage*
354service_property_set (GkdSecretService *self, DBusMessage *message)
355{
356 return NULL; /* TODO: Need to implement */
357}
358
359static void
360service_append_all_properties (GkdSecretService *self,
361 DBusMessageIter *iter)
362{
363 DBusMessageIter array;
364 DBusMessageIter dict;
365 const gchar *name;
366
367 dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{sv}", &array);
368
369 name = "Collections";
370 dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
371 dbus_message_iter_append_basic (&dict, DBUS_TYPE_STRING, &name);
372 gkd_secret_objects_append_collection_paths (self->objects, &dict, NULL);
373 dbus_message_iter_close_container (&array, &dict);
374
375 dbus_message_iter_close_container (iter, &array);
376}
377
378static DBusMessage*
379service_property_getall (GkdSecretService *self, DBusMessage *message)
380{
381 DBusMessage *reply = NULL;
382 DBusMessageIter iter;
383 const gchar *interface;
384
385 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID))
386 return NULL;
387
388 if (!gkd_dbus_interface_match (SECRET_SERVICE_INTERFACE, interface))
389 return dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
390 "Object does not have properties on interface '%s'",
391 interface);
392
393 reply = dbus_message_new_method_return (message);
394 dbus_message_iter_init_append (reply, &iter);
395 service_append_all_properties (self, &iter);
396 return reply;
397}
398
399static DBusMessage*
400service_method_open_session (GkdSecretService *self, DBusMessage *message)
401{
402 GkdSecretSession *session;
403 DBusMessage *reply = NULL;
404 const gchar *caller;
405
406 if (!dbus_message_has_signature (message, "sv"))
407 return NULL;
408
409 caller = dbus_message_get_sender (message);
410
411 /* Now we can create a session with this information */
412 session = gkd_secret_session_new (self, caller);
413 reply = gkd_secret_session_handle_open (session, message);
414
415 if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
416 gkd_secret_service_publish_dispatch (self, caller,
417 GKD_SECRET_DISPATCH (session));
418
419 g_object_unref (session);
420 return reply;
421}
422
423static DBusMessage*
424service_method_create_collection (GkdSecretService *self, DBusMessage *message)
425{
426 GckBuilder builder = GCK_BUILDER_INIT;
427 DBusMessageIter iter, array;
428 GckAttributes *attrs;
429 GkdSecretCreate *create;
430 DBusMessage *reply;
431 const gchar *path;
432 const gchar *alias;
433 const char *caller;
434 const gchar *coll;
435
436 /* Parse the incoming message */
437 if (!dbus_message_has_signature (message, "a{sv}s"))
438 return NULL;
439 if (!dbus_message_iter_init (message, &iter))
440 g_return_val_if_reached (NULL);
441 dbus_message_iter_recurse (&iter, &array);
442 if (!gkd_secret_property_parse_all (&array, SECRET_COLLECTION_INTERFACE, &builder)) {
443 gck_builder_clear (&builder);
444 return dbus_message_new_error_printf (message, DBUS_ERROR_INVALID_ARGS,
445 "Invalid properties");
446 }
447 if (!dbus_message_iter_next (&iter))
448 g_return_val_if_reached (NULL);
449 dbus_message_iter_get_basic (&iter, &alias);
450
451 /* Empty alias is no alias */
452 if (alias) {
453 if (!alias[0]) {
454 alias = NULL;
455 } else if (!g_str_equal (alias, "default")) {
456 gck_builder_clear (&builder);
457 return dbus_message_new_error (message, DBUS_ERROR_NOT_SUPPORTED,
458 "Only the 'default' alias is supported");
459 }
460 }
461
462 gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
463 attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
464
465 /* Create the prompt object, for the password */
466 caller = dbus_message_get_sender (message);
467 create = gkd_secret_create_new (self, caller, attrs, alias);
468 gck_attributes_unref (attrs);
469
470 path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (create));
471 gkd_secret_service_publish_dispatch (self, caller,
472 GKD_SECRET_DISPATCH (create));
473
474 coll = "/";
475 reply = dbus_message_new_method_return (message);
476 dbus_message_append_args (reply,
477 DBUS_TYPE_OBJECT_PATH, &coll,
478 DBUS_TYPE_OBJECT_PATH, &path,
479 DBUS_TYPE_INVALID);
480
481 g_object_unref (create);
482 return reply;
483}
484
485static DBusMessage*
486service_method_lock_service (GkdSecretService *self, DBusMessage *message)
487{
488 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INVALID))
489 return NULL;
490
491 /* TODO: Need to implement */
492 return dbus_message_new_method_return (message);
493}
494
495static DBusMessage*
496service_method_unlock (GkdSecretService *self, DBusMessage *message)
497{
498 GkdSecretUnlock *unlock;
499 DBusMessage *reply;
500 const char *caller;
501 const gchar *path;
502 int n_objpaths, i;
503 char **objpaths;
504
505 if (!dbus_message_get_args (message, NULL,
506 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &objpaths, &n_objpaths,
507 DBUS_TYPE_INVALID))
508 return NULL;
509
510 caller = dbus_message_get_sender (message);
511 unlock = gkd_secret_unlock_new (self, caller, NULL);
512 for (i = 0; i < n_objpaths; ++i)
513 gkd_secret_unlock_queue (unlock, objpaths[i]);
514 dbus_free_string_array (objpaths);
515
516 /* So do we need to prompt? */
517 if (gkd_secret_unlock_have_queued (unlock)) {
518 gkd_secret_service_publish_dispatch (self, caller,
519 GKD_SECRET_DISPATCH (unlock));
520 path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (unlock));
521
522 /* No need to prompt */
523 } else {
524 path = "/";
525 }
526
527 reply = dbus_message_new_method_return (message);
528 objpaths = gkd_secret_unlock_get_results (unlock, &n_objpaths);
529 dbus_message_append_args (reply,
530 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &objpaths, n_objpaths,
531 DBUS_TYPE_OBJECT_PATH, &path,
532 DBUS_TYPE_INVALID);
533
534 gkd_secret_unlock_reset_results (unlock);
535 g_object_unref (unlock);
536
537 return reply;
538}
539
540static DBusMessage*
541service_method_lock (GkdSecretService *self, DBusMessage *message)
542{
543 DBusMessage *reply;
544 const char *caller;
545 const gchar *prompt;
546 GckObject *collection;
547 int n_objpaths, i;
548 char **objpaths;
549 GPtrArray *array;
550
551 if (!dbus_message_get_args (message, NULL,
552 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &objpaths, &n_objpaths,
553 DBUS_TYPE_INVALID))
554 return NULL;
555
556 caller = dbus_message_get_sender (message);
557 array = g_ptr_array_new ();
558 for (i = 0; i < n_objpaths; ++i) {
559 collection = gkd_secret_objects_lookup_collection (self->objects, caller, objpaths[i]);
560 if (collection != NULL) {
561 if (gkd_secret_lock (collection, NULL)) {
562 g_ptr_array_add (array, objpaths[i]);
563 gkd_secret_objects_emit_collection_locked (self->objects,
564 collection);
565 }
566 g_object_unref (collection);
567 }
568 }
569
570 prompt = "/";
571 reply = dbus_message_new_method_return (message);
572 dbus_message_append_args (reply,
573 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &array->pdata, array->len,
574 DBUS_TYPE_OBJECT_PATH, &prompt,
575 DBUS_TYPE_INVALID);
576
577 dbus_free_string_array (objpaths);
578 return reply;
579}
580
581static DBusMessage*
582service_method_change_lock (GkdSecretService *self, DBusMessage *message)
583{
584 GkdSecretChange *change;
585 DBusMessage *reply;
586 const char *caller;
587 const gchar *path;
588 GckObject *collection;
589
590 caller = dbus_message_get_sender (message);
591 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
592 return NULL;
593
594 /* Make sure it exists */
595 collection = gkd_secret_objects_lookup_collection (self->objects, caller, path);
596 if (!collection)
597 return dbus_message_new_error (message, SECRET_ERROR_NO_SUCH_OBJECT,
598 "The collection does not exist");
599 g_object_unref (collection);
600
601 change = gkd_secret_change_new (self, caller, path);
602 path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (change));
603 gkd_secret_service_publish_dispatch (self, caller,
604 GKD_SECRET_DISPATCH (change));
605
606 reply = dbus_message_new_method_return (message);
607 dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
608
609 g_object_unref (change);
610 return reply;
611}
612
613static DBusMessage*
614service_method_read_alias (GkdSecretService *self, DBusMessage *message)
615{
616 DBusMessage *reply;
617 const char *alias;
618 gchar *path = NULL;
619 const gchar *identifier;
620 GckObject *collection = NULL;
621
622 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &alias, DBUS_TYPE_INVALID))
623 return NULL;
624
625 identifier = gkd_secret_service_get_alias (self, alias);
626 if (identifier)
627 path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, -1);
628
629 /* Make sure it actually exists */
630 if (path)
631 collection = gkd_secret_objects_lookup_collection (self->objects,
632 dbus_message_get_sender (message), path);
633 if (collection == NULL) {
634 g_free (path);
635 path = NULL;
636 } else {
637 g_object_unref (collection);
638 }
639
640 reply = dbus_message_new_method_return (message);
641 if (path == NULL)
642 path = g_strdup ("/");
643 dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
644 g_free (path);
645
646 return reply;
647}
648
649static DBusMessage*
650service_method_set_alias (GkdSecretService *self, DBusMessage *message)
651{
652 GckObject *collection;
653 gchar *identifier;
654 const char *alias;
655 const char *path;
656
657 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &alias,
658 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
659 return NULL;
660
661 g_return_val_if_fail (alias, NULL);
662 g_return_val_if_fail (path, NULL);
663
664 if (!g_str_equal (alias, "default"))
665 return dbus_message_new_error (message, DBUS_ERROR_NOT_SUPPORTED,
666 "Only the 'default' alias is supported");
667
668 /* No default collection */
669 if (g_str_equal (path, "/")) {
670 identifier = g_strdup ("");
671
672 /* Find a collection with that path */
673 } else {
674 if (!object_path_has_prefix (path, SECRET_COLLECTION_PREFIX) ||
675 !gkd_secret_util_parse_path (path, &identifier, NULL))
676 return dbus_message_new_error (message, DBUS_ERROR_INVALID_ARGS,
677 "Invalid collection object path");
678
679 collection = gkd_secret_objects_lookup_collection (self->objects,
680 dbus_message_get_sender (message), path);
681 if (collection == NULL) {
682 g_free (identifier);
683 return dbus_message_new_error (message, SECRET_ERROR_NO_SUCH_OBJECT,
684 "No such collection exists");
685 }
686
687 g_object_unref (collection);
688 }
689
690 gkd_secret_service_set_alias (self, alias, identifier);
691 g_free (identifier);
692
693 return dbus_message_new_method_return (message);
694}
695
696static DBusMessage*
697service_method_create_with_master_password (GkdSecretService *self, DBusMessage *message)
698{
699 GckBuilder builder = GCK_BUILDER_INIT;
700 DBusError derr = DBUS_ERROR_INIT;
701 DBusMessageIter iter, array;
702 DBusMessage *reply = NULL;
703 GkdSecretSecret *secret = NULL;
704 GckAttributes *attrs = NULL;
705 GError *error = NULL;
706 gchar *path;
707
708 /* Parse the incoming message */
709 if (!dbus_message_has_signature (message, "a{sv}(oayays)"))
710 return NULL;
711 if (!dbus_message_iter_init (message, &iter))
712 g_return_val_if_reached (NULL);
713 dbus_message_iter_recurse (&iter, &array);
714 if (!gkd_secret_property_parse_all (&array, SECRET_COLLECTION_INTERFACE, &builder)) {
715 gck_builder_clear (&builder);
716 return dbus_message_new_error (message, DBUS_ERROR_INVALID_ARGS,
717 "Invalid properties argument");
718 }
719 dbus_message_iter_next (&iter);
720 secret = gkd_secret_secret_parse (self, message, &iter, &derr);
721 if (secret == NULL) {
722 gck_builder_clear (&builder);
723 return gkd_secret_error_to_reply (message, &derr);
724 }
725
726 gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
727 attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
728 path = gkd_secret_create_with_secret (attrs, secret, &error);
729 gck_attributes_unref (attrs);
730 gkd_secret_secret_free (secret);
731
732 if (path == NULL)
733 return gkd_secret_propagate_error (message, "Couldn't create collection", error);
734
735 /* Notify the callers that a collection was created */
736 gkd_secret_service_emit_collection_created (self, path);
737
738 reply = dbus_message_new_method_return (message);
739 dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
740 g_free (path);
741
742 return reply;
743}
744
745static DBusMessage*
746service_method_change_with_master_password (GkdSecretService *self, DBusMessage *message)
747{
748 DBusError derr = DBUS_ERROR_INIT;
749 GkdSecretSecret *original, *master;
750 GckObject *collection;
751 DBusMessageIter iter;
752 DBusMessage *reply;
753 GError *error = NULL;
754 const gchar *path;
755
756 /* Parse the incoming message */
757 if (!dbus_message_has_signature (message, "o(oayays)(oayays)"))
758 return NULL;
759 if (!dbus_message_iter_init (message, &iter))
760 g_return_val_if_reached (NULL);
761 dbus_message_iter_get_basic (&iter, &path);
762 dbus_message_iter_next (&iter);
763 original = gkd_secret_secret_parse (self, message, &iter, &derr);
764 if (original == NULL)
765 return gkd_secret_error_to_reply (message, &derr);
766 dbus_message_iter_next (&iter);
767 master = gkd_secret_secret_parse (self, message, &iter, &derr);
768 if (master == NULL) {
769 gkd_secret_secret_free (original);
770 return gkd_secret_error_to_reply (message, &derr);
771 }
772
773 /* Make sure we have such a collection */
774 collection = gkd_secret_objects_lookup_collection (self->objects,
775 dbus_message_get_sender (message),
776 path);
777
778 /* No such collection */
779 if (collection == NULL)
780 reply = dbus_message_new_error (message, SECRET_ERROR_NO_SUCH_OBJECT,
781 "The collection does not exist");
782
783 /* Success */
784 else if (gkd_secret_change_with_secrets (collection, NULL, original, master, &error))
785 reply = dbus_message_new_method_return (message);
786
787 /* Failure */
788 else
789 reply = gkd_secret_propagate_error (message, "Couldn't change collection password", error);
790
791 gkd_secret_secret_free (original);
792 gkd_secret_secret_free (master);
793
794 if (collection)
795 g_object_unref (collection);
796
797 return reply;
798}
799
800static DBusMessage*
801service_method_unlock_with_master_password (GkdSecretService *self, DBusMessage *message)
802{
803 DBusError derr = DBUS_ERROR_INIT;
804 GkdSecretSecret *master;
805 GError *error = NULL;
806 GckObject *collection;
807 DBusMessageIter iter;
808 DBusMessage *reply;
809 const gchar *path;
810
811 /* Parse the incoming message */
812 if (!dbus_message_has_signature (message, "o(oayays)"))
813 return NULL;
814 if (!dbus_message_iter_init (message, &iter))
815 g_return_val_if_reached (NULL);
816 dbus_message_iter_get_basic (&iter, &path);
817 dbus_message_iter_next (&iter);
818 master = gkd_secret_secret_parse (self, message, &iter, &derr);
819 if (master == NULL)
820 return gkd_secret_error_to_reply (message, &derr);
821
822 /* Make sure we have such a collection */
823 collection = gkd_secret_objects_lookup_collection (self->objects,
824 dbus_message_get_sender (message),
825 path);
826
827 /* No such collection */
828 if (collection == NULL) {
829 reply = dbus_message_new_error (message, SECRET_ERROR_NO_SUCH_OBJECT,
830 "The collection does not exist");
831
832 /* Success */
833 } else if (gkd_secret_unlock_with_secret (collection, master, &error)) {
834 reply = dbus_message_new_method_return (message);
835 gkd_secret_objects_emit_collection_locked (self->objects, collection);
836
837 /* Failure */
838 } else {
839 reply = gkd_secret_propagate_error (message, "Couldn't unlock collection", error);
840 }
841
842 gkd_secret_secret_free (master);
843
844 if (collection)
845 g_object_unref (collection);
846
847 return reply;
848}
849
850static void
851on_each_path_append_to_array (GkdSecretObjects *self,
852 const gchar *path,
853 GckObject *object,
854 gpointer user_data)
855{
856 GPtrArray *array = user_data;
857 g_ptr_array_add (array, g_strdup (path));
858}
859
860static DBusMessage *
861service_introspect (GkdSecretService *self,
862 DBusMessage *message)
863{
864 GPtrArray *names;
865 DBusMessage *reply;
866 ServiceClient *client;
867 const gchar *caller;
868 const gchar *path;
869 GHashTableIter iter;
870
871 names = g_ptr_array_new_with_free_func (g_free);
872 gkd_secret_objects_foreach_collection (self->objects, message,
873 on_each_path_append_to_array,
874 names);
875
876 /* Lookup all sessions and prompts for this client */
877 caller = dbus_message_get_sender (message);
878 if (caller != NULL) {
879 client = g_hash_table_lookup (self->clients, caller);
880 if (client != NULL) {
881 g_hash_table_iter_init (&iter, client->dispatch);
882 while (g_hash_table_iter_next (&iter, (gpointer *)&path, NULL))
883 g_ptr_array_add (names, g_strdup (path));
884 }
885 }
886
887 g_ptr_array_add (names, NULL);
888
889 reply = gkd_dbus_introspect_handle (message, gkd_secret_introspect_service,
890 (const gchar **)names->pdata);
891
892 g_ptr_array_unref (names);
893 return reply;
894}
895
896static DBusMessage*
897service_message_handler (GkdSecretService *self, DBusMessage *message)
898{
899 g_return_val_if_fail (message, NULL);
900 g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
901
902 /* org.freedesktop.Secret.Service.OpenSession() */
903 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "OpenSession"))
904 return service_method_open_session (self, message);
905
906 /* org.freedesktop.Secret.Service.CreateCollection() */
907 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "CreateCollection"))
908 return service_method_create_collection (self, message);
909
910 /* org.freedesktop.Secret.Service.LockService() */
911 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "LockService"))
912 return service_method_lock_service (self, message);
913
914 /* org.freedesktop.Secret.Service.SearchItems() */
915 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "SearchItems"))
916 return gkd_secret_objects_handle_search_items (self->objects, message, NULL);
917
918 /* org.freedesktop.Secret.Service.GetSecrets() */
919 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "GetSecrets"))
920 return gkd_secret_objects_handle_get_secrets (self->objects, message);
921
922 /* org.freedesktop.Secret.Service.Unlock() */
923 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "Unlock"))
924 return service_method_unlock (self, message);
925
926 /* org.freedesktop.Secret.Service.Lock() */
927 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "Lock"))
928 return service_method_lock (self, message);
929
930 /* org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface.ChangeWithPrompt() */
931 if (dbus_message_is_method_call (message, INTERNAL_SERVICE_INTERFACE, "ChangeWithPrompt") ||
932 dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "ChangeLock"))
933 return service_method_change_lock (self, message);
934
935 /* org.freedesktop.Secret.Service.ReadAlias() */
936 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "ReadAlias"))
937 return service_method_read_alias (self, message);
938
939 /* org.freedesktop.Secret.Service.SetAlias() */
940 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "SetAlias"))
941 return service_method_set_alias (self, message);
942
943 /* org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface.CreateWithMasterPassword */
944 if (dbus_message_is_method_call (message, INTERNAL_SERVICE_INTERFACE, "CreateWithMasterPassword"))
945 return service_method_create_with_master_password (self, message);
946
947 /* org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface.ChangeWithMasterPassword() */
948 if (dbus_message_is_method_call (message, INTERNAL_SERVICE_INTERFACE, "ChangeWithMasterPassword"))
949 return service_method_change_with_master_password (self, message);
950
951 /* org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface.UnlockWithMasterPassword() */
952 if (dbus_message_is_method_call (message, INTERNAL_SERVICE_INTERFACE, "UnlockWithMasterPassword"))
953 return service_method_unlock_with_master_password (self, message);
954
955 /* org.freedesktop.DBus.Properties.Get() */
956 if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Get"))
957 return service_property_get (self, message);
958
959 /* org.freedesktop.DBus.Properties.Set() */
960 else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Set"))
961 return service_property_set (self, message);
962
963 /* org.freedesktop.DBus.Properties.GetAll() */
964 else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "GetAll"))
965 return service_property_getall (self, message);
966
967 /* org.freedesktop.DBus.Introspectable.Introspect() */
968 else if (dbus_message_has_interface (message, DBUS_INTERFACE_INTROSPECTABLE))
969 return service_introspect (self, message);
970
971 return NULL;
972}
973
974static gboolean
975root_dispatch_message (GkdSecretService *self,
976 DBusMessage *message)
977{
978 DBusMessage *reply = NULL;
979
980 if (dbus_message_has_interface (message, DBUS_INTERFACE_INTROSPECTABLE))
981 reply = gkd_dbus_introspect_handle (message, gkd_secret_introspect_root, NULL);
982
983 if (reply != NULL) {
984 dbus_connection_send (self->connection, reply, NULL);
985 dbus_message_unref (reply);
986 return TRUE;
987 }
988
989 return FALSE;
990}
991
992static void
993service_dispatch_message (GkdSecretService *self, DBusMessage *message)
994{
995 DBusMessage *reply = NULL;
996 const gchar *caller;
997 ServiceClient *client;
998 const gchar *path;
999 gpointer object;
1000
1001 g_assert (GKD_SECRET_IS_SERVICE (self));
1002 g_assert (message);
1003
1004 /* The first thing we do is try to allocate a client context */
1005 caller = dbus_message_get_sender (message);
1006 if (caller == NULL) {
1007 reply = dbus_message_new_error (message, DBUS_ERROR_FAILED,
1008 "Could not not identify calling client application");
1009 dbus_connection_send (self->connection, reply, NULL);
1010 dbus_message_unref (reply);
1011 return;
1012 }
1013
1014 client = g_hash_table_lookup (self->clients, caller);
1015 if (client == NULL) {
1016 initialize_service_client (self, message);
1017 return; /* This function called again, when client is initialized */
1018 }
1019
1020 path = dbus_message_get_path (message);
1021 g_return_if_fail (path);
1022
1023 /* Dispatched to a session or prompt */
1024 if (object_path_has_prefix (path, SECRET_SESSION_PREFIX) ||
1025 object_path_has_prefix (path, SECRET_PROMPT_PREFIX)) {
1026 object = g_hash_table_lookup (client->dispatch, path);
1027 if (object == NULL)
1028 reply = gkd_secret_error_no_such_object (message);
1029 else
1030 reply = gkd_secret_dispatch_message (GKD_SECRET_DISPATCH (object), message);
1031
1032 /* Dispatched to a collection, off it goes */
1033 } else if (object_path_has_prefix (path, SECRET_COLLECTION_PREFIX) ||
1034 object_path_has_prefix (path, SECRET_ALIAS_PREFIX)) {
1035 reply = gkd_secret_objects_dispatch (self->objects, message);
1036
1037 /* Addressed to the service */
1038 } else if (g_str_equal (path, SECRET_SERVICE_PATH)) {
1039 reply = service_message_handler (self, message);
1040 }
1041
1042 /* Should we send an error? */
1043 if (!reply && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL) {
1044 if (!dbus_message_get_no_reply (message)) {
1045 reply = dbus_message_new_error_printf (message, DBUS_ERROR_UNKNOWN_METHOD,
1046 "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist\n",
1047 dbus_message_get_member (message),
1048 dbus_message_get_signature (message),
1049 dbus_message_get_interface (message));
1050 }
1051 }
1052
1053 if (reply) {
1054 dbus_connection_send (self->connection, reply, NULL);
1055 dbus_message_unref (reply);
1056 }
1057}
1058
1059static DBusHandlerResult
1060gkd_secret_service_filter_handler (DBusConnection *conn, DBusMessage *message, gpointer user_data)
1061{
1062 GkdSecretService *self = user_data;
1063 const gchar *object_name;
1064 const gchar *old_owner;
1065 const gchar *new_owner;
1066 const gchar *path;
1067 const gchar *interface;
1068
1069 g_return_val_if_fail (conn && message, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
1070 g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
1071
1072 /* org.freedesktop.DBus.NameOwnerChanged(STRING name, STRING old_owner, STRING new_owner) */
1073 if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged") &&
1074 dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &object_name,
1075 DBUS_TYPE_STRING, &old_owner, DBUS_TYPE_STRING, &new_owner,
1076 DBUS_TYPE_INVALID)) {
1077
1078 /*
1079 * A peer is connecting or disconnecting from the bus,
1080 * remove any client info, when client gone.
1081 */
1082
1083 g_return_val_if_fail (object_name && new_owner, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
1084 if (g_str_equal (new_owner, "") && object_name[0] == ':')
1085 g_hash_table_remove (self->clients, object_name);
1086
1087 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1088 }
1089
1090 /*
1091 * If the path is a within our object tree, then we do our own dispatch.
1092 */
1093 path = dbus_message_get_path (message);
1094 switch (dbus_message_get_type (message)) {
1095
1096 /* Dispatch any method call on our interfaces, for our objects */
1097 case DBUS_MESSAGE_TYPE_METHOD_CALL:
1098 if (path != NULL && g_str_equal (path, "/")) {
1099 if (root_dispatch_message (self, message))
1100 return DBUS_HANDLER_RESULT_HANDLED;
1101 }
1102
1103 if (object_path_has_prefix (path, SECRET_SERVICE_PATH)) {
1104 interface = dbus_message_get_interface (message);
1105 if (interface == NULL ||
1106 g_str_has_prefix (interface, SECRET_INTERFACE_PREFIX) ||
1107 g_str_equal (interface, DBUS_INTERFACE_PROPERTIES) ||
1108 g_str_equal (interface, INTERNAL_SERVICE_INTERFACE) ||
1109 g_str_equal (interface, DBUS_INTERFACE_INTROSPECTABLE)) {
1110 service_dispatch_message (self, message);
1111 return DBUS_HANDLER_RESULT_HANDLED;
1112 }
1113 }
1114 break;
1115
1116 /* Dispatch any signal for one of our objects */
1117 case DBUS_MESSAGE_TYPE_SIGNAL:
1118 if (object_path_has_prefix (path, SECRET_SERVICE_PATH)) {
1119 service_dispatch_message (self, message);
1120 return DBUS_HANDLER_RESULT_HANDLED;
1121 }
1122 break;
1123
1124 default:
1125 break;
1126 }
1127
1128 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1129}
1130
1131/* -----------------------------------------------------------------------------
1132 * OBJECT
1133 */
1134
1135static GObject*
1136gkd_secret_service_constructor (GType type, guint n_props, GObjectConstructParam *props)
1137{
1138 GkdSecretService *self = GKD_SECRET_SERVICE (G_OBJECT_CLASS (gkd_secret_service_parent_class)->constructor(type, n_props, props));
1139 DBusError error = DBUS_ERROR_INIT;
1140 GckSlot *slot = NULL;
1141 guint i;
1142
1143 g_return_val_if_fail (self, NULL);
1144 g_return_val_if_fail (self->connection, NULL);
1145
1146 /* Find the pkcs11-slot parameter */
1147 for (i = 0; !slot && i < n_props; ++i) {
1148 if (g_str_equal (props[i].pspec->name, "pkcs11-slot"))
1149 slot = g_value_get_object (props[i].value);
1150 }
1151
1152 /* Create our objects proxy */
1153 g_return_val_if_fail (GCK_IS_SLOT (slot), NULL);
1154 self->objects = g_object_new (GKD_SECRET_TYPE_OBJECTS,
1155 "pkcs11-slot", slot, "service", self, NULL);
1156
1157 /* Register for signals that let us know when clients leave the bus */
1158 self->match_rule = g_strdup_printf ("type='signal',member=NameOwnerChanged,"
1159 "interface='" DBUS_INTERFACE_DBUS "'");
1160 dbus_bus_add_match (self->connection, self->match_rule, &error);
1161 if (dbus_error_is_set (&error)) {
1162 g_warning ("couldn't listen for NameOwnerChanged signal on session bus: %s", error.message);
1163 dbus_error_free (&error);
1164 g_free (self->match_rule);
1165 self->match_rule = NULL;
1166 }
1167
1168 if (!dbus_connection_add_filter (self->connection, gkd_secret_service_filter_handler, self, NULL))
1169 g_return_val_if_reached (NULL);
1170
1171 return G_OBJECT (self);
1172}
1173
1174static void
1175gkd_secret_service_init (GkdSecretService *self)
1176{
1177 self->clients = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_client);
1178 self->aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1179}
1180
1181static void
1182gkd_secret_service_dispose (GObject *obj)
1183{
1184 GkdSecretService *self = GKD_SECRET_SERVICE (obj);
1185
1186 if (self->match_rule) {
1187 g_return_if_fail (self->connection);
1188 dbus_bus_remove_match (self->connection, self->match_rule, NULL);
1189 g_free (self->match_rule);
1190 self->match_rule = NULL;
1191 }
1192
1193 /* Closes all the clients */
1194 g_hash_table_remove_all (self->clients);
1195
1196 /* Hide all the objects */
1197 if (self->objects) {
1198 g_object_run_dispose (G_OBJECT (self->objects));
1199 g_object_unref (self->objects);
1200 self->objects = NULL;
1201 }
1202
1203 if (self->connection) {
1204 dbus_connection_remove_filter (self->connection, gkd_secret_service_filter_handler, self);
1205 dbus_connection_unref (self->connection);
1206 self->connection = NULL;
1207 }
1208
1209 if (self->internal_session) {
1210 dispose_and_unref (self->internal_session);
1211 self->internal_session = NULL;
1212 }
1213
1214 G_OBJECT_CLASS (gkd_secret_service_parent_class)->dispose (obj);
1215}
1216
1217static void
1218gkd_secret_service_finalize (GObject *obj)
1219{
1220 GkdSecretService *self = GKD_SECRET_SERVICE (obj);
1221
1222 g_assert (g_hash_table_size (self->clients) == 0);
1223 g_hash_table_destroy (self->clients);
1224 self->clients = NULL;
1225
1226 g_hash_table_destroy (self->aliases);
1227 self->aliases = NULL;
1228
1229 G_OBJECT_CLASS (gkd_secret_service_parent_class)->finalize (obj);
1230}
1231
1232static void
1233gkd_secret_service_set_property (GObject *obj, guint prop_id, const GValue *value,
1234 GParamSpec *pspec)
1235{
1236 GkdSecretService *self = GKD_SECRET_SERVICE (obj);
1237
1238 switch (prop_id) {
1239 case PROP_CONNECTION:
1240 g_return_if_fail (!self->connection);
1241 self->connection = g_value_dup_boxed (value);
1242 g_return_if_fail (self->connection);
1243 break;
1244 case PROP_PKCS11_SLOT:
1245 g_return_if_fail (!self->objects);
1246 break;
1247 default:
1248 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1249 break;
1250 }
1251}
1252
1253static void
1254gkd_secret_service_get_property (GObject *obj, guint prop_id, GValue *value,
1255 GParamSpec *pspec)
1256{
1257 GkdSecretService *self = GKD_SECRET_SERVICE (obj);
1258
1259 switch (prop_id) {
1260 case PROP_CONNECTION:
1261 g_value_set_boxed (value, gkd_secret_service_get_connection (self));
1262 break;
1263 case PROP_PKCS11_SLOT:
1264 g_value_set_object (value, gkd_secret_service_get_pkcs11_slot (self));
1265 break;
1266 default:
1267 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1268 break;
1269 }
1270}
1271
1272static void
1273gkd_secret_service_class_init (GkdSecretServiceClass *klass)
1274{
1275 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1276
1277 gobject_class->constructor = gkd_secret_service_constructor;
1278 gobject_class->dispose = gkd_secret_service_dispose;
1279 gobject_class->finalize = gkd_secret_service_finalize;
1280 gobject_class->set_property = gkd_secret_service_set_property;
1281 gobject_class->get_property = gkd_secret_service_get_property;
1282
1283 g_object_class_install_property (gobject_class, PROP_CONNECTION,
1284 g_param_spec_boxed ("connection", "Connection", "DBus Connection",
1285 GKD_DBUS_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1286
1287 g_object_class_install_property (gobject_class, PROP_PKCS11_SLOT,
1288 g_param_spec_object ("pkcs11-slot", "Pkcs11 Slot", "PKCS#11 slot that we use for secrets",
1289 GCK_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1290}
1291
1292/* -----------------------------------------------------------------------------
1293 * PUBLIC
1294 */
1295
1296void
1297gkd_secret_service_send (GkdSecretService *self, DBusMessage *message)
1298{
1299 g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1300 dbus_connection_send (self->connection, message, NULL);
1301}
1302
1303GkdSecretObjects*
1304gkd_secret_service_get_objects (GkdSecretService *self)
1305{
1306 g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1307 return self->objects;
1308}
1309
1310DBusConnection*
1311gkd_secret_service_get_connection (GkdSecretService *self)
1312{
1313 g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1314 return self->connection;
1315}
1316
1317GckSlot*
1318gkd_secret_service_get_pkcs11_slot (GkdSecretService *self)
1319{
1320 g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1321 return gkd_secret_objects_get_pkcs11_slot (self->objects);
1322}
1323
1324static gboolean
1325log_into_pkcs11_session (GckSession *session, GError **error)
1326{
1327 GckSessionInfo *sess;
1328 GckTokenInfo *info;
1329 GckSlot *slot;
1330 gboolean login;
1331
1332 /* Perform the necessary 'user' login to secrets token. Doesn't unlock anything */
1333 slot = gck_session_get_slot (session);
1334 info = gck_slot_get_token_info (slot);
1335 login = info && (info->flags & CKF_LOGIN_REQUIRED);
1336 gck_token_info_free (info);
1337 g_object_unref (slot);
1338
1339 if (login) {
1340 sess = gck_session_get_info (session);
1341 if (sess->state == CKS_RO_USER_FUNCTIONS ||
1342 sess->state == CKS_RW_USER_FUNCTIONS)
1343 login = FALSE;
1344 gck_session_info_free (sess);
1345 }
1346
1347 if (login && !gck_session_login (session, CKU_USER, NULL, 0, NULL, error))
1348 return FALSE;
1349
1350 return TRUE;
1351}
1352
1353GckSession*
1354gkd_secret_service_get_pkcs11_session (GkdSecretService *self, const gchar *caller)
1355{
1356 ServiceClient *client;
1357 GError *error = NULL;
1358 GckSlot *slot;
1359
1360 g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1361 g_return_val_if_fail (caller, NULL);
1362
1363 client = g_hash_table_lookup (self->clients, caller);
1364 g_return_val_if_fail (client, NULL);
1365
1366 /* Open a new session if necessary */
1367 if (!client->pkcs11_session) {
1368 slot = gkd_secret_service_get_pkcs11_slot (self);
1369 client->pkcs11_session = gck_slot_open_session_full (slot, GCK_SESSION_READ_WRITE,
1370 CKF_G_APPLICATION_SESSION, &client->app,
1371 NULL, NULL, &error);
1372 if (!client->pkcs11_session) {
1373 g_warning ("couldn't open pkcs11 session for secret service: %s",
1374 egg_error_message (error));
1375 g_clear_error (&error);
1376 return NULL;
1377 }
1378
1379 if (!log_into_pkcs11_session (client->pkcs11_session, &error)) {
1380 g_warning ("couldn't log in to pkcs11 session for secret service: %s",
1381 egg_error_message (error));
1382 g_clear_error (&error);
1383 g_object_unref (client->pkcs11_session);
1384 client->pkcs11_session = NULL;
1385 return NULL;
1386 }
1387 }
1388
1389 return client->pkcs11_session;
1390}
1391
1392GckSession*
1393gkd_secret_service_internal_pkcs11_session (GkdSecretService *self)
1394{
1395 GError *error = NULL;
1396 GckSlot *slot;
1397
1398 g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1399
1400 if (self->internal_session)
1401 return self->internal_session;
1402
1403 slot = gkd_secret_service_get_pkcs11_slot (self);
1404 self->internal_session = gck_slot_open_session_full (slot, GCK_SESSION_READ_WRITE,
1405 0, NULL, NULL, NULL, &error);
1406 if (!self->internal_session) {
1407 g_warning ("couldn't open pkcs11 session for secret service: %s",
1408 egg_error_message (error));
1409 g_clear_error (&error);
1410 return NULL;
1411 }
1412
1413 if (!log_into_pkcs11_session (self->internal_session, &error)) {
1414 g_warning ("couldn't log in to pkcs11 session for secret service: %s",
1415 egg_error_message (error));
1416 g_clear_error (&error);
1417 g_object_unref (self->internal_session);
1418 self->internal_session = NULL;
1419 return NULL;
1420 }
1421
1422 return self->internal_session;
1423}
1424
1425GkdSecretSession*
1426gkd_secret_service_lookup_session (GkdSecretService *self, const gchar *path,
1427 const gchar *caller)
1428{
1429 ServiceClient *client;
1430 gpointer object;
1431
1432 g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1433 g_return_val_if_fail (path, NULL);
1434 g_return_val_if_fail (caller, NULL);
1435
1436 client = g_hash_table_lookup (self->clients, caller);
1437 g_return_val_if_fail (client, NULL);
1438
1439 object = g_hash_table_lookup (client->dispatch, path);
1440 if (object == NULL || !GKD_SECRET_IS_SESSION (object))
1441 return NULL;
1442
1443 return GKD_SECRET_SESSION (object);
1444}
1445
1446void
1447gkd_secret_service_close_session (GkdSecretService *self, GkdSecretSession *session)
1448{
1449 ServiceClient *client;
1450 const gchar *caller;
1451 const gchar *path;
1452
1453 g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1454 g_return_if_fail (GKD_SECRET_IS_SESSION (session));
1455
1456 caller = gkd_secret_session_get_caller (session);
1457 client = g_hash_table_lookup (self->clients, caller);
1458 g_return_if_fail (client);
1459
1460 path = gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (session));
1461 g_hash_table_remove (client->dispatch, path);
1462}
1463
1464const gchar*
1465gkd_secret_service_get_alias (GkdSecretService *self, const gchar *alias)
1466{
1467 const gchar *identifier;
1468
1469 g_return_val_if_fail (GKD_SECRET_IS_SERVICE (self), NULL);
1470 g_return_val_if_fail (alias != NULL, NULL);
1471
1472 identifier = g_hash_table_lookup (self->aliases, alias);
1473 if (!identifier) {
1474 if (g_str_equal (alias, "default")) {
1475 update_default (self, TRUE);
1476 identifier = g_hash_table_lookup (self->aliases, alias);
1477
1478 /* Default to to 'login' if no default keyring */
1479 if (identifier == NULL) {
1480 identifier = "login";
1481 g_hash_table_replace (self->aliases, g_strdup (alias),
1482 g_strdup (identifier));
1483 }
1484
1485 } else if (g_str_equal (alias, "session")) {
1486 identifier = "session";
1487 g_hash_table_replace (self->aliases, g_strdup (alias),
1488 g_strdup (identifier));
1489
1490 /* TODO: We should be using CKA_G_LOGIN_COLLECTION */
1491 } else if (g_str_equal (alias, "login")) {
1492 identifier = "login";
1493 g_hash_table_replace (self->aliases, g_strdup (alias),
1494 g_strdup (identifier));
1495 }
1496 }
1497
1498 return identifier;
1499}
1500
1501void
1502gkd_secret_service_set_alias (GkdSecretService *self, const gchar *alias,
1503 const gchar *identifier)
1504{
1505 g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1506 g_return_if_fail (alias);
1507
1508 g_hash_table_replace (self->aliases, g_strdup (alias), g_strdup (identifier));
1509
1510 if (g_str_equal (alias, "default"))
1511 store_default (self);
1512}
1513
1514void
1515gkd_secret_service_publish_dispatch (GkdSecretService *self, const gchar *caller,
1516 GkdSecretDispatch *object)
1517{
1518 ServiceClient *client;
1519 const gchar *path;
1520
1521 g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1522 g_return_if_fail (caller);
1523 g_return_if_fail (GKD_SECRET_IS_DISPATCH (object));
1524
1525 /* Take ownership of the session */
1526 client = g_hash_table_lookup (self->clients, caller);
1527 g_return_if_fail (client);
1528 path = gkd_secret_dispatch_get_object_path (object);
1529 g_return_if_fail (!g_hash_table_lookup (client->dispatch, path));
1530 g_hash_table_replace (client->dispatch, (gpointer)path, g_object_ref (object));
1531}
1532
1533static void
1534emit_collections_properties_changed (GkdSecretService *self)
1535{
1536 const gchar *iface = SECRET_SERVICE_INTERFACE;
1537 DBusMessage *message;
1538 DBusMessageIter array;
1539 DBusMessageIter iter;
1540
1541 message = dbus_message_new_signal (SECRET_SERVICE_PATH,
1542 DBUS_INTERFACE_PROPERTIES,
1543 "PropertiesChanged");
1544
1545 dbus_message_iter_init_append (message, &iter);
1546 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &iface);
1547 service_append_all_properties (self, &iter);
1548 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &array);
1549 dbus_message_iter_close_container (&iter, &array);
1550
1551 if (!dbus_connection_send (self->connection, message, NULL))
1552 g_return_if_reached ();
1553 dbus_message_unref (message);
1554}
1555
1556void
1557gkd_secret_service_emit_collection_created (GkdSecretService *self,
1558 const gchar *collection_path)
1559{
1560 DBusMessage *message;
1561
1562 g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1563 g_return_if_fail (collection_path != NULL);
1564
1565 message = dbus_message_new_signal (SECRET_SERVICE_PATH,
1566 SECRET_SERVICE_INTERFACE,
1567 "CollectionCreated");
1568 dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &collection_path,
1569 DBUS_TYPE_INVALID);
1570
1571 if (!dbus_connection_send (self->connection, message, NULL))
1572 g_return_if_reached ();
1573 dbus_message_unref (message);
1574
1575 emit_collections_properties_changed (self);
1576}
1577
1578void
1579gkd_secret_service_emit_collection_deleted (GkdSecretService *self,
1580 const gchar *collection_path)
1581{
1582 DBusMessage *message;
1583
1584 g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
1585 g_return_if_fail (collection_path != NULL);
1586
1587 message = dbus_message_new_signal (SECRET_SERVICE_PATH,
1588 SECRET_SERVICE_INTERFACE,
1589 "CollectionDeleted");
1590 dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &collection_path,
1591 DBUS_TYPE_INVALID);
1592
1593 if (!dbus_connection_send (self->connection, message, NULL))
1594 g_return_if_reached ();
1595 dbus_message_unref (message);
1596
1597 emit_collections_properties_changed (self);
1598}
01599
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2012-05-16 17:39:27 +0000
+++ .pc/applied-patches 2013-03-14 13:26:21 +0000
@@ -1,2 +1,4 @@
100git_fix_searchitems_method.patch
200git_fix_introspection.patch
103_kfreebsd.patch303_kfreebsd.patch
204_nodisplay_autostart.patch404_nodisplay_autostart.patch
35
=== modified file 'daemon/dbus/gkd-secret-introspect.c'
--- daemon/dbus/gkd-secret-introspect.c 2012-05-16 17:39:27 +0000
+++ daemon/dbus/gkd-secret-introspect.c 2013-03-14 13:26:21 +0000
@@ -63,7 +63,7 @@
63 " <interface name='org.freedesktop.Secret.Collection'>\n"63 " <interface name='org.freedesktop.Secret.Collection'>\n"
64 " <property name='Items' type='ao' access='read'/>\n"64 " <property name='Items' type='ao' access='read'/>\n"
65 " <property name='Label' type='s' access='readwrite'/>\n"65 " <property name='Label' type='s' access='readwrite'/>\n"
66 " <property name='Locked' type='s' access='read'/>\n"66 " <property name='Locked' type='b' access='read'/>\n"
67 " <property name='Created' type='t' access='read'/>\n"67 " <property name='Created' type='t' access='read'/>\n"
68 " <property name='Modified' type='t' access='read'/>\n"68 " <property name='Modified' type='t' access='read'/>\n"
69 " <method name='Delete'>\n"69 " <method name='Delete'>\n"
@@ -71,8 +71,7 @@
71 " </method>\n"71 " </method>\n"
72 " <method name='SearchItems'>\n"72 " <method name='SearchItems'>\n"
73 " <arg name='attributes' type='a{ss}' direction='in'/>\n"73 " <arg name='attributes' type='a{ss}' direction='in'/>\n"
74 " <arg name='unlocked' type='ao' direction='out'/>\n"74 " <arg name='results' type='ao' direction='out'/>\n"
75 " <arg name='locked' type='ao' direction='out'/>\n"
76 " </method>\n"75 " </method>\n"
77 " <method name='CreateItem'>\n"76 " <method name='CreateItem'>\n"
78 " <arg name='props' type='a{sv}' direction='in'/>\n"77 " <arg name='props' type='a{sv}' direction='in'/>\n"
7978
=== modified file 'daemon/dbus/gkd-secret-objects.c'
--- daemon/dbus/gkd-secret-objects.c 2013-03-07 11:39:17 +0000
+++ daemon/dbus/gkd-secret-objects.c 2013-03-14 13:26:21 +0000
@@ -542,7 +542,7 @@
542static DBusMessage*542static DBusMessage*
543collection_method_search_items (GkdSecretObjects *self, GckObject *object, DBusMessage *message)543collection_method_search_items (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
544{544{
545 return gkd_secret_objects_handle_search_items (self, message, dbus_message_get_path (message));545 return gkd_secret_objects_handle_search_items (self, message, dbus_message_get_path (message), FALSE);
546}546}
547547
548static GckObject*548static GckObject*
@@ -1314,8 +1314,10 @@
1314}1314}
13151315
1316DBusMessage*1316DBusMessage*
1317gkd_secret_objects_handle_search_items (GkdSecretObjects *self, DBusMessage *message,1317gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
1318 const gchar *base)1318 DBusMessage *message,
1319 const gchar *base,
1320 gboolean separate_locked)
1319{1321{
1320 GckBuilder builder = GCK_BUILDER_INIT;1322 GckBuilder builder = GCK_BUILDER_INIT;
1321 DBusMessageIter iter;1323 DBusMessageIter iter;
@@ -1385,23 +1387,31 @@
1385 items = gck_objects_from_handle_array (session, data, n_data / sizeof (CK_OBJECT_HANDLE));1387 items = gck_objects_from_handle_array (session, data, n_data / sizeof (CK_OBJECT_HANDLE));
1386 g_free (data);1388 g_free (data);
13871389
1390 /* Prepare the reply message */
1391 reply = dbus_message_new_method_return (message);
1392 dbus_message_iter_init_append (reply, &iter);
1393
1388 /* Filter out the locked items */1394 /* Filter out the locked items */
1389 item_cleanup_search_results (session, items, &locked, &unlocked);1395 if (separate_locked) {
13901396 item_cleanup_search_results (session, items, &locked, &unlocked);
1391 /* Prepare the reply message */1397
1392 reply = dbus_message_new_method_return (message);1398 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
1393 dbus_message_iter_init_append (reply, &iter);1399 objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_iter, &array);
13941400 dbus_message_iter_close_container (&iter, &array);
1395 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);1401
1396 objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_iter, &array);1402 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
1397 dbus_message_iter_close_container (&iter, &array);1403 objects_foreach_item (self, locked, NULL, on_object_path_append_to_iter, &array);
13981404 dbus_message_iter_close_container (&iter, &array);
1399 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);1405
1400 objects_foreach_item (self, locked, NULL, on_object_path_append_to_iter, &array);1406 g_list_free (locked);
1401 dbus_message_iter_close_container (&iter, &array);1407 g_list_free (unlocked);
14021408
1403 g_list_free (locked);1409 } else {
1404 g_list_free (unlocked);1410 dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
1411 objects_foreach_item (self, items, NULL, on_object_path_append_to_iter, &array);
1412 dbus_message_iter_close_container (&iter, &array);
1413 }
1414
1405 gck_list_unref_free (items);1415 gck_list_unref_free (items);
14061416
1407 return reply;1417 return reply;
14081418
=== modified file 'daemon/dbus/gkd-secret-objects.h'
--- daemon/dbus/gkd-secret-objects.h 2012-08-13 12:39:40 +0000
+++ daemon/dbus/gkd-secret-objects.h 2013-03-14 13:26:21 +0000
@@ -55,7 +55,8 @@
5555
56DBusMessage* gkd_secret_objects_handle_search_items (GkdSecretObjects *self,56DBusMessage* gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
57 DBusMessage *message,57 DBusMessage *message,
58 const gchar *base);58 const gchar *base,
59 gboolean separate_locked);
5960
60DBusMessage* gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self,61DBusMessage* gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self,
61 DBusMessage *message);62 DBusMessage *message);
6263
=== modified file 'daemon/dbus/gkd-secret-service.c'
--- daemon/dbus/gkd-secret-service.c 2012-08-24 10:32:10 +0000
+++ daemon/dbus/gkd-secret-service.c 2013-03-14 13:26:21 +0000
@@ -913,7 +913,7 @@
913913
914 /* org.freedesktop.Secret.Service.SearchItems() */914 /* org.freedesktop.Secret.Service.SearchItems() */
915 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "SearchItems"))915 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "SearchItems"))
916 return gkd_secret_objects_handle_search_items (self->objects, message, NULL);916 return gkd_secret_objects_handle_search_items (self->objects, message, NULL, TRUE);
917917
918 /* org.freedesktop.Secret.Service.GetSecrets() */918 /* org.freedesktop.Secret.Service.GetSecrets() */
919 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "GetSecrets"))919 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "GetSecrets"))
920920
=== modified file 'debian/changelog'
--- debian/changelog 2013-03-07 11:39:17 +0000
+++ debian/changelog 2013-03-14 13:26:21 +0000
@@ -1,3 +1,12 @@
1gnome-keyring (3.6.3-0ubuntu2) raring; urgency=low
2
3 * debian/patches/00git_fix_searchitems_method.patch:
4 Upstream patch to fix return value of Collection.SearchItems().
5 * debian/patches/00git_fix_introspection.patch:
6 Upstream patch to fix introspection of some D-Bus methods.
7
8 -- Dmitry Shachnev <mitya57@ubuntu.com> Thu, 14 Mar 2013 17:18:23 +0400
9
1gnome-keyring (3.6.3-0ubuntu1) raring; urgency=low10gnome-keyring (3.6.3-0ubuntu1) raring; urgency=low
211
3 * New upstream release12 * New upstream release
413
=== added file 'debian/patches/00git_fix_introspection.patch'
--- debian/patches/00git_fix_introspection.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/00git_fix_introspection.patch 2013-03-14 13:26:21 +0000
@@ -0,0 +1,26 @@
1Author: Dmitry Shachnev <mitya57@ubuntu.com>
2Description: Fix introspection of some D-Bus methods
3Forwarded: yes
4Last-Update: 2013-03-10
5
6--- a/daemon/dbus/gkd-secret-introspect.c
7+++ b/daemon/dbus/gkd-secret-introspect.c
8@@ -63,7 +63,7 @@
9 " <interface name='org.freedesktop.Secret.Collection'>\n"
10 " <property name='Items' type='ao' access='read'/>\n"
11 " <property name='Label' type='s' access='readwrite'/>\n"
12- " <property name='Locked' type='s' access='read'/>\n"
13+ " <property name='Locked' type='b' access='read'/>\n"
14 " <property name='Created' type='t' access='read'/>\n"
15 " <property name='Modified' type='t' access='read'/>\n"
16 " <method name='Delete'>\n"
17@@ -71,8 +71,7 @@
18 " </method>\n"
19 " <method name='SearchItems'>\n"
20 " <arg name='attributes' type='a{ss}' direction='in'/>\n"
21- " <arg name='unlocked' type='ao' direction='out'/>\n"
22- " <arg name='locked' type='ao' direction='out'/>\n"
23+ " <arg name='results' type='ao' direction='out'/>\n"
24 " </method>\n"
25 " <method name='CreateItem'>\n"
26 " <arg name='props' type='a{sv}' direction='in'/>\n"
027
=== added file 'debian/patches/00git_fix_searchitems_method.patch'
--- debian/patches/00git_fix_searchitems_method.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/00git_fix_searchitems_method.patch 2013-03-14 13:26:21 +0000
@@ -0,0 +1,99 @@
1Description: Only return one object path list from Collection.SearchItems()
2 In the Secret Service dbus interface the SearchItems method of the
3 Collection interface only returns one list of object paths, unlike
4 SearchItems on the Service interface which splits its return values
5 by locked and unlocked items.
6Origin: upstream, https://git.gnome.org/browse/gnome-keyring/commit/?id=ddb87ccad9
7Last-Update: 2013-03-10
8
9--- a/daemon/dbus/gkd-secret-objects.c
10+++ b/daemon/dbus/gkd-secret-objects.c
11@@ -542,7 +542,7 @@
12 static DBusMessage*
13 collection_method_search_items (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
14 {
15- return gkd_secret_objects_handle_search_items (self, message, dbus_message_get_path (message));
16+ return gkd_secret_objects_handle_search_items (self, message, dbus_message_get_path (message), FALSE);
17 }
18
19 static GckObject*
20@@ -1314,8 +1314,10 @@
21 }
22
23 DBusMessage*
24-gkd_secret_objects_handle_search_items (GkdSecretObjects *self, DBusMessage *message,
25- const gchar *base)
26+gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
27+ DBusMessage *message,
28+ const gchar *base,
29+ gboolean separate_locked)
30 {
31 GckBuilder builder = GCK_BUILDER_INIT;
32 DBusMessageIter iter;
33@@ -1385,23 +1387,31 @@
34 items = gck_objects_from_handle_array (session, data, n_data / sizeof (CK_OBJECT_HANDLE));
35 g_free (data);
36
37- /* Filter out the locked items */
38- item_cleanup_search_results (session, items, &locked, &unlocked);
39-
40 /* Prepare the reply message */
41 reply = dbus_message_new_method_return (message);
42 dbus_message_iter_init_append (reply, &iter);
43
44- dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
45- objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_iter, &array);
46- dbus_message_iter_close_container (&iter, &array);
47-
48- dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
49- objects_foreach_item (self, locked, NULL, on_object_path_append_to_iter, &array);
50- dbus_message_iter_close_container (&iter, &array);
51+ /* Filter out the locked items */
52+ if (separate_locked) {
53+ item_cleanup_search_results (session, items, &locked, &unlocked);
54+
55+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
56+ objects_foreach_item (self, unlocked, NULL, on_object_path_append_to_iter, &array);
57+ dbus_message_iter_close_container (&iter, &array);
58+
59+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
60+ objects_foreach_item (self, locked, NULL, on_object_path_append_to_iter, &array);
61+ dbus_message_iter_close_container (&iter, &array);
62+
63+ g_list_free (locked);
64+ g_list_free (unlocked);
65+
66+ } else {
67+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &array);
68+ objects_foreach_item (self, items, NULL, on_object_path_append_to_iter, &array);
69+ dbus_message_iter_close_container (&iter, &array);
70+ }
71
72- g_list_free (locked);
73- g_list_free (unlocked);
74 gck_list_unref_free (items);
75
76 return reply;
77--- a/daemon/dbus/gkd-secret-objects.h
78+++ b/daemon/dbus/gkd-secret-objects.h
79@@ -55,7 +55,8 @@
80
81 DBusMessage* gkd_secret_objects_handle_search_items (GkdSecretObjects *self,
82 DBusMessage *message,
83- const gchar *base);
84+ const gchar *base,
85+ gboolean separate_locked);
86
87 DBusMessage* gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self,
88 DBusMessage *message);
89--- a/daemon/dbus/gkd-secret-service.c
90+++ b/daemon/dbus/gkd-secret-service.c
91@@ -913,7 +913,7 @@
92
93 /* org.freedesktop.Secret.Service.SearchItems() */
94 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "SearchItems"))
95- return gkd_secret_objects_handle_search_items (self->objects, message, NULL);
96+ return gkd_secret_objects_handle_search_items (self->objects, message, NULL, TRUE);
97
98 /* org.freedesktop.Secret.Service.GetSecrets() */
99 if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "GetSecrets"))
0100
=== modified file 'debian/patches/series'
--- debian/patches/series 2012-05-16 17:39:27 +0000
+++ debian/patches/series 2013-03-14 13:26:21 +0000
@@ -1,2 +1,4 @@
100git_fix_searchitems_method.patch
200git_fix_introspection.patch
103_kfreebsd.patch303_kfreebsd.patch
204_nodisplay_autostart.patch404_nodisplay_autostart.patch

Subscribers

People subscribed via source and target branches