Line data Source code
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, see
18 : * <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "gkm-secret-object.h"
24 :
25 : #include "gkm/gkm-attributes.h"
26 : #include "gkm/gkm-session.h"
27 : #include "gkm/gkm-transaction.h"
28 :
29 : #include "pkcs11/pkcs11i.h"
30 :
31 : #include <glib/gi18n.h>
32 :
33 : enum {
34 : PROP_0,
35 : PROP_LABEL,
36 : PROP_IDENTIFIER,
37 : PROP_CREATED,
38 : PROP_MODIFIED
39 : };
40 :
41 : struct _GkmSecretObjectPrivate {
42 : gchar *identifier;
43 : gchar *label;
44 : glong created;
45 : glong modified;
46 : };
47 :
48 121875 : G_DEFINE_TYPE_WITH_PRIVATE (GkmSecretObject, gkm_secret_object, GKM_TYPE_OBJECT);
49 :
50 : /* -----------------------------------------------------------------------------
51 : * INTERNAL
52 : */
53 :
54 : static gboolean
55 8 : complete_set_label (GkmTransaction *transaction, GObject *obj, gpointer user_data)
56 : {
57 8 : GkmSecretObject *self = GKM_SECRET_OBJECT (obj);
58 8 : gchar *old_label = user_data;
59 :
60 8 : if (gkm_transaction_get_failed (transaction)) {
61 1 : g_free (self->pv->label);
62 1 : self->pv->label = old_label;
63 : } else {
64 7 : gkm_object_notify_attribute (GKM_OBJECT (obj), CKA_LABEL);
65 7 : g_object_notify (G_OBJECT (obj), "label");
66 7 : g_free (old_label);
67 : }
68 :
69 8 : return TRUE;
70 : }
71 :
72 : static void
73 8 : begin_set_label (GkmSecretObject *self, GkmTransaction *transaction, gchar *label)
74 : {
75 8 : g_assert (GKM_IS_SECRET_OBJECT (self));
76 8 : g_assert (!gkm_transaction_get_failed (transaction));
77 :
78 8 : gkm_secret_object_begin_modified (GKM_SECRET_OBJECT (self), transaction);
79 8 : gkm_transaction_add (transaction, self, complete_set_label, self->pv->label);
80 8 : self->pv->label = label;
81 8 : }
82 :
83 : static gchar*
84 2445 : register_identifier (GkmSecretObjectClass *klass, const gchar *identifier)
85 : {
86 : gchar *result;
87 : gint i;
88 :
89 2445 : g_assert (klass);
90 2445 : g_assert (identifier);
91 :
92 2445 : if (!klass->identifiers)
93 2193 : return g_strdup (identifier);
94 :
95 254 : for (i = 0; i < G_MAXINT; ++i) {
96 254 : if (i == 0)
97 252 : result = g_strdup (identifier);
98 : else
99 2 : result = g_strdup_printf ("%s_%d", identifier, i);
100 254 : if (g_hash_table_lookup (klass->identifiers, result)) {
101 2 : g_free (result);
102 : } else {
103 252 : g_hash_table_insert (klass->identifiers, result, result);
104 252 : return result;
105 : }
106 : }
107 :
108 0 : g_assert_not_reached ();
109 : }
110 :
111 : static void
112 2445 : unregister_identifier (GkmSecretObjectClass *klass, gchar *identifier)
113 : {
114 2445 : g_assert (klass);
115 2445 : g_assert (identifier);
116 :
117 2445 : if (klass->identifiers)
118 252 : g_hash_table_remove (klass->identifiers, identifier);
119 2445 : g_free (identifier);
120 2445 : }
121 :
122 : /* -----------------------------------------------------------------------------
123 : * OBJECT
124 : */
125 :
126 : static CK_RV
127 5147 : gkm_secret_object_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
128 : {
129 5147 : GkmSecretObject *self = GKM_SECRET_OBJECT (base);
130 :
131 5147 : switch (attr->type) {
132 0 : case CKA_MODIFIABLE:
133 0 : return gkm_attribute_set_bool (attr, TRUE);
134 :
135 4967 : case CKA_ID:
136 4967 : return gkm_attribute_set_string (attr, gkm_secret_object_get_identifier (self));
137 :
138 19 : case CKA_LABEL:
139 19 : return gkm_attribute_set_string (attr, gkm_secret_object_get_label (self));
140 :
141 133 : case CKA_G_LOCKED:
142 133 : return gkm_attribute_set_bool (attr, gkm_secret_object_is_locked (self, session));
143 :
144 3 : case CKA_G_CREATED:
145 3 : return gkm_attribute_set_time (attr, gkm_secret_object_get_created (self));
146 :
147 3 : case CKA_G_MODIFIED:
148 3 : return gkm_attribute_set_time (attr, gkm_secret_object_get_modified (self));
149 : }
150 :
151 22 : return GKM_OBJECT_CLASS (gkm_secret_object_parent_class)->get_attribute (base, session, attr);
152 : }
153 :
154 : static void
155 8 : gkm_secret_object_set_attribute (GkmObject *base, GkmSession *session,
156 : GkmTransaction *transaction, CK_ATTRIBUTE_PTR attr)
157 : {
158 8 : GkmSecretObject *self = GKM_SECRET_OBJECT (base);
159 : gchar *label;
160 : CK_RV rv;
161 :
162 8 : switch (attr->type) {
163 :
164 8 : case CKA_LABEL:
165 : /* Check that the object is not locked */
166 8 : if (gkm_secret_object_is_locked (self, session))
167 0 : rv = CKR_USER_NOT_LOGGED_IN;
168 : else
169 8 : rv = gkm_attribute_get_string (attr, &label);
170 8 : if (rv != CKR_OK)
171 0 : gkm_transaction_fail (transaction, rv);
172 : else
173 8 : begin_set_label (self, transaction, label);
174 8 : return;
175 : }
176 :
177 0 : GKM_OBJECT_CLASS (gkm_secret_object_parent_class)->set_attribute (base, session, transaction, attr);
178 : }
179 :
180 : static gboolean
181 4 : gkm_secret_object_real_is_locked (GkmSecretObject *self, GkmSession *session)
182 : {
183 : /* Derived classes override us */
184 4 : return FALSE;
185 : }
186 :
187 : static void
188 2445 : gkm_secret_object_init (GkmSecretObject *self)
189 : {
190 2445 : self->pv = gkm_secret_object_get_instance_private (self);
191 2445 : }
192 :
193 : static GObject*
194 2445 : gkm_secret_object_constructor (GType type, guint n_props, GObjectConstructParam *props)
195 : {
196 2445 : GkmSecretObject *self = GKM_SECRET_OBJECT (G_OBJECT_CLASS (gkm_secret_object_parent_class)->constructor(type, n_props, props));
197 2445 : g_return_val_if_fail (self, NULL);
198 :
199 : /* Must be created with an identifier */
200 2445 : g_return_val_if_fail (self->pv->identifier, NULL);
201 :
202 2445 : return G_OBJECT (self);
203 : }
204 :
205 : static void
206 4890 : gkm_secret_object_set_property (GObject *obj, guint prop_id, const GValue *value,
207 : GParamSpec *pspec)
208 : {
209 4890 : GkmSecretObjectClass *klass = GKM_SECRET_OBJECT_GET_CLASS (obj);
210 4890 : GkmSecretObject *self = GKM_SECRET_OBJECT (obj);
211 : const gchar *identifier;
212 :
213 4890 : switch (prop_id) {
214 2445 : case PROP_LABEL:
215 2445 : gkm_secret_object_set_label (self, g_value_get_string (value));
216 2445 : break;
217 2445 : case PROP_IDENTIFIER:
218 2445 : g_return_if_fail (!self->pv->identifier);
219 2445 : identifier = g_value_get_string (value);
220 2445 : g_return_if_fail (identifier);
221 2445 : self->pv->identifier = register_identifier (klass, identifier);
222 2445 : break;
223 0 : case PROP_CREATED:
224 0 : gkm_secret_object_set_created (self, g_value_get_long (value));
225 0 : break;
226 0 : case PROP_MODIFIED:
227 0 : gkm_secret_object_set_modified (self, g_value_get_long (value));
228 0 : break;
229 0 : default:
230 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
231 0 : break;
232 : }
233 : }
234 :
235 : static void
236 0 : gkm_secret_object_get_property (GObject *obj, guint prop_id, GValue *value,
237 : GParamSpec *pspec)
238 : {
239 0 : GkmSecretObject *self = GKM_SECRET_OBJECT (obj);
240 :
241 0 : switch (prop_id) {
242 0 : case PROP_LABEL:
243 0 : g_value_set_string (value, gkm_secret_object_get_label (self));
244 0 : break;
245 0 : case PROP_IDENTIFIER:
246 0 : g_value_set_string (value, gkm_secret_object_get_identifier (self));
247 0 : break;
248 0 : case PROP_CREATED:
249 0 : g_value_set_long (value, gkm_secret_object_get_created (self));
250 0 : break;
251 0 : case PROP_MODIFIED:
252 0 : g_value_set_long (value, gkm_secret_object_get_modified (self));
253 0 : break;
254 0 : default:
255 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
256 0 : break;
257 : }
258 0 : }
259 :
260 : static void
261 2445 : gkm_secret_object_finalize (GObject *obj)
262 : {
263 2445 : GkmSecretObjectClass *klass = GKM_SECRET_OBJECT_GET_CLASS (obj);
264 2445 : GkmSecretObject *self = GKM_SECRET_OBJECT (obj);
265 :
266 2445 : if (self->pv->identifier)
267 2445 : unregister_identifier (klass, self->pv->identifier);
268 2445 : self->pv->identifier = NULL;
269 :
270 2445 : g_free (self->pv->label);
271 2445 : self->pv->label = NULL;
272 :
273 2445 : self->pv->created = 0;
274 2445 : self->pv->modified = 0;
275 :
276 2445 : G_OBJECT_CLASS (gkm_secret_object_parent_class)->finalize (obj);
277 2445 : }
278 :
279 : static void
280 34 : gkm_secret_object_class_init (GkmSecretObjectClass *klass)
281 : {
282 34 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
283 34 : GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
284 :
285 34 : gobject_class->constructor = gkm_secret_object_constructor;
286 34 : gobject_class->finalize = gkm_secret_object_finalize;
287 34 : gobject_class->set_property = gkm_secret_object_set_property;
288 34 : gobject_class->get_property = gkm_secret_object_get_property;
289 :
290 34 : gkm_class->get_attribute = gkm_secret_object_get_attribute;
291 34 : gkm_class->set_attribute = gkm_secret_object_set_attribute;
292 :
293 34 : klass->is_locked = gkm_secret_object_real_is_locked;
294 :
295 34 : g_object_class_install_property (gobject_class, PROP_IDENTIFIER,
296 : g_param_spec_string ("identifier", "Identifier", "Object Identifier",
297 : NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
298 :
299 34 : g_object_class_install_property (gobject_class, PROP_LABEL,
300 : g_param_spec_string ("label", "Label", "Object Label",
301 : "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
302 :
303 34 : g_object_class_install_property (gobject_class, PROP_CREATED,
304 : g_param_spec_long ("created", "Created", "Object Create Time",
305 : 0, G_MAXLONG, 0, G_PARAM_READABLE));
306 :
307 34 : g_object_class_install_property (gobject_class, PROP_MODIFIED,
308 : g_param_spec_long ("modified", "Modified", "Object Modify Time",
309 : 0, G_MAXLONG, 0, G_PARAM_READABLE));
310 34 : }
311 :
312 : /* -----------------------------------------------------------------------------
313 : * PUBLIC
314 : */
315 :
316 : void
317 34 : gkm_secret_object_class_unique_identifiers (GkmSecretObjectClass *klass)
318 : {
319 34 : if (!klass->identifiers)
320 34 : klass->identifiers = g_hash_table_new (g_str_hash, g_str_equal);
321 34 : }
322 :
323 : const gchar*
324 9732 : gkm_secret_object_get_identifier (GkmSecretObject *self)
325 : {
326 9732 : g_return_val_if_fail (GKM_IS_SECRET_OBJECT (self), NULL);
327 9732 : return self->pv->identifier;
328 : }
329 :
330 : const gchar*
331 81 : gkm_secret_object_get_label (GkmSecretObject *self)
332 : {
333 81 : g_return_val_if_fail (GKM_IS_SECRET_OBJECT (self), NULL);
334 81 : return self->pv->label;
335 : }
336 :
337 : void
338 2733 : gkm_secret_object_set_label (GkmSecretObject *self, const gchar *label)
339 : {
340 2733 : g_return_if_fail (GKM_IS_SECRET_OBJECT (self));
341 :
342 2733 : if (self->pv->label == label)
343 0 : return;
344 :
345 2733 : g_free (self->pv->label);
346 2733 : self->pv->label = g_strdup (label);
347 2733 : g_object_notify (G_OBJECT (self), "label");
348 : }
349 :
350 : glong
351 67 : gkm_secret_object_get_created (GkmSecretObject *self)
352 : {
353 67 : g_return_val_if_fail (GKM_IS_SECRET_OBJECT (self), 0);
354 67 : return self->pv->created;
355 : }
356 :
357 : void
358 295 : gkm_secret_object_set_created (GkmSecretObject *self, glong when)
359 : {
360 295 : g_return_if_fail (GKM_IS_SECRET_OBJECT (self));
361 :
362 295 : if (when < 0) {
363 0 : when = g_get_real_time () / G_USEC_PER_SEC;
364 : }
365 :
366 295 : self->pv->created = when;
367 295 : g_object_notify (G_OBJECT (self), "created");
368 : }
369 :
370 : void
371 20 : gkm_secret_object_mark_created (GkmSecretObject *self)
372 : {
373 20 : g_return_if_fail (GKM_IS_SECRET_OBJECT (self));
374 :
375 20 : gkm_secret_object_set_created (self, g_get_real_time () / G_USEC_PER_SEC);
376 : }
377 :
378 : glong
379 40915 : gkm_secret_object_get_modified (GkmSecretObject *self)
380 : {
381 40915 : g_return_val_if_fail (GKM_IS_SECRET_OBJECT (self), 0);
382 40915 : return self->pv->modified;
383 : }
384 :
385 : void
386 2275 : gkm_secret_object_set_modified (GkmSecretObject *self, glong when)
387 : {
388 2275 : g_return_if_fail (GKM_IS_SECRET_OBJECT (self));
389 2275 : self->pv->modified = when;
390 2275 : g_object_notify (G_OBJECT (self), "modified");
391 : }
392 :
393 : static gboolean
394 18 : complete_set_modified (GkmTransaction *transaction,
395 : GObject *obj,
396 : gpointer user_data)
397 : {
398 18 : GkmSecretObject *self = GKM_SECRET_OBJECT (obj);
399 18 : glong *old_modified = user_data;
400 :
401 18 : if (gkm_transaction_get_failed (transaction)) {
402 2 : self->pv->modified = *old_modified;
403 :
404 : } else {
405 16 : gkm_object_notify_attribute (GKM_OBJECT (obj), CKA_G_MODIFIED);
406 16 : g_object_notify (G_OBJECT (obj), "modified");
407 : }
408 :
409 18 : g_free (old_modified);
410 18 : return TRUE;
411 : }
412 :
413 : void
414 18 : gkm_secret_object_begin_modified (GkmSecretObject *self,
415 : GkmTransaction *transaction)
416 : {
417 18 : g_return_if_fail (!gkm_transaction_get_failed (transaction));
418 18 : gkm_transaction_add (transaction, self, complete_set_modified,
419 18 : g_memdup (&self->pv->modified, sizeof (gulong)));
420 :
421 18 : self->pv->modified = g_get_real_time () / G_USEC_PER_SEC;
422 : }
423 :
424 : gboolean
425 201 : gkm_secret_object_is_locked (GkmSecretObject *self, GkmSession *session)
426 : {
427 201 : g_return_val_if_fail (GKM_IS_SECRET_OBJECT (self), TRUE);
428 201 : g_return_val_if_fail (GKM_SECRET_OBJECT_GET_CLASS (self)->is_locked, TRUE);
429 201 : return GKM_SECRET_OBJECT_GET_CLASS (self)->is_locked (self, session);
430 : }
|