Line data Source code
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, see
18 : * <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "gkd-secret-property.h"
24 :
25 : #include "pkcs11/pkcs11i.h"
26 :
27 : #include <string.h>
28 :
29 :
30 : typedef enum _DataType {
31 : DATA_TYPE_INVALID = 0,
32 :
33 : /*
34 : * The attribute is a CK_BBOOL.
35 : * Property is DBUS_TYPE_BOOLEAN
36 : */
37 : DATA_TYPE_BOOL,
38 :
39 : /*
40 : * The attribute is in the format: "%Y%m%d%H%M%S00"
41 : * Property is DBUS_TYPE_UINT64 since 1970 epoch.
42 : */
43 : DATA_TYPE_TIME,
44 :
45 : /*
46 : * The attribute is a CK_UTF8_CHAR string, not null-terminated
47 : * Property is a DBUS_TYPE_STRING
48 : */
49 : DATA_TYPE_STRING,
50 :
51 : /*
52 : * The attribute is in the format: name\0value\0name2\0value2
53 : * Property is dbus dictionary of strings: a{ss}
54 : */
55 : DATA_TYPE_FIELDS
56 : } DataType;
57 :
58 : /* -----------------------------------------------------------------------------
59 : * INTERNAL
60 : */
61 :
62 : static gboolean
63 57 : property_to_attribute (const gchar *prop_name, const gchar *interface,
64 : CK_ATTRIBUTE_TYPE *attr_type, DataType *data_type)
65 : {
66 57 : g_return_val_if_fail (prop_name, FALSE);
67 57 : g_assert (attr_type);
68 57 : g_assert (data_type);
69 :
70 : /* If an interface is desired, check that it matches, and remove */
71 57 : if (interface) {
72 4 : if (!g_str_has_prefix (prop_name, interface))
73 0 : return FALSE;
74 :
75 4 : prop_name += strlen (interface);
76 4 : if (prop_name[0] != '.')
77 0 : return FALSE;
78 4 : ++prop_name;
79 : }
80 :
81 57 : if (g_str_equal (prop_name, "Label")) {
82 9 : *attr_type = CKA_LABEL;
83 9 : *data_type = DATA_TYPE_STRING;
84 :
85 : /* Non-standard property for type schema */
86 48 : } else if (g_str_equal (prop_name, "Type")) {
87 1 : *attr_type = CKA_G_SCHEMA;
88 1 : *data_type = DATA_TYPE_STRING;
89 :
90 47 : } else if (g_str_equal (prop_name, "Locked")) {
91 44 : *attr_type = CKA_G_LOCKED;
92 44 : *data_type = DATA_TYPE_BOOL;
93 :
94 3 : } else if (g_str_equal (prop_name, "Created")) {
95 1 : *attr_type = CKA_G_CREATED;
96 1 : *data_type = DATA_TYPE_TIME;
97 :
98 2 : } else if (g_str_equal (prop_name, "Modified")) {
99 1 : *attr_type = CKA_G_MODIFIED;
100 1 : *data_type = DATA_TYPE_TIME;
101 :
102 1 : } else if (g_str_equal (prop_name, "Attributes")) {
103 1 : *attr_type = CKA_G_FIELDS;
104 1 : *data_type = DATA_TYPE_FIELDS;
105 :
106 : } else {
107 0 : return FALSE;
108 : }
109 :
110 57 : return TRUE;
111 : }
112 :
113 : static gboolean
114 49 : attribute_to_property (CK_ATTRIBUTE_TYPE attr_type, const gchar **prop_name, DataType *data_type)
115 : {
116 49 : g_assert (prop_name);
117 49 : g_assert (data_type);
118 :
119 49 : switch (attr_type) {
120 1 : case CKA_LABEL:
121 1 : *prop_name = "Label";
122 1 : *data_type = DATA_TYPE_STRING;
123 1 : break;
124 : /* Non-standard property for type schema */
125 1 : case CKA_G_SCHEMA:
126 1 : *prop_name = "Type";
127 1 : *data_type = DATA_TYPE_STRING;
128 1 : break;
129 44 : case CKA_G_LOCKED:
130 44 : *prop_name = "Locked";
131 44 : *data_type = DATA_TYPE_BOOL;
132 44 : break;
133 1 : case CKA_G_CREATED:
134 1 : *prop_name = "Created";
135 1 : *data_type = DATA_TYPE_TIME;
136 1 : break;
137 1 : case CKA_G_MODIFIED:
138 1 : *prop_name = "Modified";
139 1 : *data_type = DATA_TYPE_TIME;
140 1 : break;
141 1 : case CKA_G_FIELDS:
142 1 : *prop_name = "Attributes";
143 1 : *data_type = DATA_TYPE_FIELDS;
144 1 : break;
145 0 : default:
146 0 : return FALSE;
147 : };
148 :
149 49 : return TRUE;
150 : }
151 :
152 : typedef GVariant * (*IterAppendFunc) (const GckAttribute *);
153 : typedef gboolean (*IterGetFunc) (GVariant *, gulong, GckBuilder *);
154 :
155 : static GVariant *
156 2 : iter_append_string (const GckAttribute *attr)
157 : {
158 2 : g_assert (attr);
159 :
160 2 : if (attr->length == 0) {
161 1 : return g_variant_new_string ("");
162 : } else {
163 1 : return g_variant_new_take_string (g_strndup ((const gchar*)attr->value, attr->length));
164 : }
165 : }
166 :
167 : static gboolean
168 6 : iter_get_string (GVariant *variant,
169 : gulong attr_type,
170 : GckBuilder *builder)
171 : {
172 : const char *value;
173 :
174 6 : g_assert (variant != NULL);
175 6 : g_assert (builder != NULL);
176 :
177 6 : value = g_variant_get_string (variant, NULL);
178 6 : if (value == NULL)
179 0 : value = "";
180 6 : gck_builder_add_string (builder, attr_type, value);
181 6 : return TRUE;
182 : }
183 :
184 : static GVariant *
185 44 : iter_append_bool (const GckAttribute *attr)
186 : {
187 44 : g_assert (attr);
188 :
189 44 : return g_variant_new_boolean (gck_attribute_get_boolean (attr));
190 : }
191 :
192 : static gboolean
193 0 : iter_get_bool (GVariant *variant,
194 : gulong attr_type,
195 : GckBuilder *builder)
196 : {
197 : gboolean value;
198 :
199 0 : g_assert (variant != NULL);
200 0 : g_assert (builder != NULL);
201 :
202 0 : value = g_variant_get_boolean (variant);
203 0 : gck_builder_add_boolean (builder, attr_type, value);
204 0 : return TRUE;
205 : }
206 :
207 : static GVariant *
208 2 : iter_append_time (const GckAttribute *attr)
209 : {
210 : guint64 value;
211 : struct tm tm;
212 : gchar buf[15];
213 : time_t time;
214 :
215 2 : g_assert (attr);
216 :
217 2 : if (attr->length == 0) {
218 0 : value = 0;
219 :
220 2 : } else if (!attr->value || attr->length != 16) {
221 0 : g_warning ("invalid length of time attribute");
222 0 : value = 0;
223 :
224 : } else {
225 2 : memset (&tm, 0, sizeof (tm));
226 2 : memcpy (buf, attr->value, 14);
227 2 : buf[14] = 0;
228 :
229 2 : if (!strptime(buf, "%Y%m%d%H%M%S", &tm)) {
230 0 : g_warning ("invalid format of time attribute");
231 0 : value = 0;
232 : } else {
233 : /* Convert to seconds since epoch */
234 2 : time = timegm (&tm);
235 2 : if (time < 0) {
236 0 : g_warning ("invalid time attribute");
237 0 : value = 0;
238 : } else {
239 2 : value = time;
240 : }
241 : }
242 : }
243 :
244 2 : return g_variant_new_uint64 (value);
245 : }
246 :
247 : static gboolean
248 0 : iter_get_time (GVariant *variant,
249 : gulong attr_type,
250 : GckBuilder *builder)
251 : {
252 : time_t time;
253 : struct tm tm;
254 : gchar buf[20];
255 : guint64 value;
256 :
257 0 : g_assert (variant != NULL);
258 0 : g_assert (builder != NULL);
259 :
260 0 : value = g_variant_get_uint64 (variant);
261 0 : if (value == 0) {
262 0 : gck_builder_add_empty (builder, attr_type);
263 0 : return TRUE;
264 : }
265 :
266 0 : time = value;
267 0 : if (!gmtime_r (&time, &tm))
268 0 : g_return_val_if_reached (FALSE);
269 :
270 0 : if (!strftime (buf, sizeof (buf), "%Y%m%d%H%M%S00", &tm))
271 0 : g_return_val_if_reached (FALSE);
272 :
273 0 : gck_builder_add_data (builder, attr_type, (const guchar *)buf, 16);
274 0 : return TRUE;
275 : }
276 :
277 : static GVariant *
278 1 : iter_append_fields (const GckAttribute *attr)
279 : {
280 : const gchar *ptr;
281 : const gchar *last;
282 : const gchar *name;
283 : gsize n_name;
284 : const gchar *value;
285 : gsize n_value;
286 : gchar *name_string, *value_string;
287 : GVariantBuilder builder;
288 :
289 1 : g_assert (attr);
290 :
291 1 : ptr = (gchar*)attr->value;
292 1 : last = ptr + attr->length;
293 1 : g_return_val_if_fail (ptr || last == ptr, NULL);
294 :
295 1 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
296 :
297 1 : while (ptr && ptr != last) {
298 0 : g_assert (ptr < last);
299 :
300 0 : name = ptr;
301 0 : ptr = memchr (ptr, 0, last - ptr);
302 0 : if (ptr == NULL) /* invalid */
303 0 : break;
304 :
305 0 : n_name = ptr - name;
306 0 : value = ++ptr;
307 0 : ptr = memchr (ptr, 0, last - ptr);
308 0 : if (ptr == NULL) /* invalid */
309 0 : break;
310 :
311 0 : n_value = ptr - value;
312 0 : ++ptr;
313 :
314 0 : name_string = g_strndup (name, n_name);
315 0 : value_string = g_strndup (value, n_value);
316 :
317 0 : g_variant_builder_add (&builder, "{ss}", name_string, value_string);
318 :
319 0 : g_free (name_string);
320 0 : g_free (value_string);
321 : }
322 :
323 1 : return g_variant_builder_end (&builder);
324 : }
325 :
326 : static gboolean
327 8 : iter_get_fields (GVariant *variant,
328 : gulong attr_type,
329 : GckBuilder *builder)
330 : {
331 : GString *result;
332 : const gchar *key, *value;
333 : GVariantIter iter;
334 :
335 8 : g_assert (variant != NULL);
336 8 : g_assert (builder != NULL);
337 :
338 8 : g_return_val_if_fail (g_variant_type_is_array (g_variant_get_type (variant)), FALSE);
339 :
340 8 : result = g_string_new ("");
341 8 : g_variant_iter_init (&iter, variant);
342 :
343 14 : while (g_variant_iter_next (&iter, "{&s&s}", &key, &value)) {
344 : /* Key */
345 6 : g_string_append (result, key);
346 : g_string_append_c (result, '\0');
347 :
348 : /* Value */
349 6 : g_string_append (result, value);
350 : g_string_append_c (result, '\0');
351 : }
352 :
353 8 : gck_builder_add_data (builder, attr_type, (const guchar *)result->str, result->len);
354 8 : g_string_free (result, TRUE);
355 8 : return TRUE;
356 : }
357 :
358 : static GVariant *
359 49 : iter_append_variant (DataType data_type,
360 : const GckAttribute *attr)
361 : {
362 49 : IterAppendFunc func = NULL;
363 :
364 49 : g_assert (attr);
365 :
366 49 : switch (data_type) {
367 2 : case DATA_TYPE_STRING:
368 2 : func = iter_append_string;
369 2 : break;
370 44 : case DATA_TYPE_BOOL:
371 44 : func = iter_append_bool;
372 44 : break;
373 2 : case DATA_TYPE_TIME:
374 2 : func = iter_append_time;
375 2 : break;
376 1 : case DATA_TYPE_FIELDS:
377 1 : func = iter_append_fields;
378 1 : break;
379 0 : default:
380 0 : g_assert (FALSE);
381 : break;
382 : }
383 :
384 49 : return (func) (attr);
385 : }
386 :
387 : static gboolean
388 6 : iter_get_variant (GVariant *variant,
389 : DataType data_type,
390 : gulong attr_type,
391 : GckBuilder *builder)
392 : {
393 6 : IterGetFunc func = NULL;
394 : gboolean ret;
395 : const GVariantType *sig;
396 :
397 6 : g_assert (variant != NULL);
398 6 : g_assert (builder != NULL);
399 :
400 6 : switch (data_type) {
401 6 : case DATA_TYPE_STRING:
402 6 : func = iter_get_string;
403 6 : sig = G_VARIANT_TYPE_STRING;
404 6 : break;
405 0 : case DATA_TYPE_BOOL:
406 0 : func = iter_get_bool;
407 0 : sig = G_VARIANT_TYPE_BOOLEAN;
408 0 : break;
409 0 : case DATA_TYPE_TIME:
410 0 : func = iter_get_time;
411 0 : sig = G_VARIANT_TYPE_UINT64;
412 0 : break;
413 0 : case DATA_TYPE_FIELDS:
414 0 : func = iter_get_fields;
415 0 : sig = G_VARIANT_TYPE ("a{ss}");
416 0 : break;
417 0 : default:
418 0 : g_assert (FALSE);
419 : break;
420 : }
421 :
422 6 : ret = g_variant_type_equal (g_variant_get_type (variant), sig);
423 6 : if (ret == FALSE)
424 0 : return FALSE;
425 :
426 6 : return (func) (variant, attr_type, builder);
427 : }
428 :
429 : /* -----------------------------------------------------------------------------
430 : * PUBLIC
431 : */
432 :
433 : gboolean
434 51 : gkd_secret_property_get_type (const gchar *property, CK_ATTRIBUTE_TYPE *type)
435 : {
436 : DataType data_type;
437 :
438 51 : g_return_val_if_fail (property, FALSE);
439 51 : g_return_val_if_fail (type, FALSE);
440 :
441 51 : return property_to_attribute (property, NULL, type, &data_type);
442 : }
443 :
444 : gboolean
445 4 : gkd_secret_property_parse_all (GVariant *array,
446 : const gchar *interface,
447 : GckBuilder *builder)
448 : {
449 : CK_ATTRIBUTE_TYPE attr_type;
450 : const char *name;
451 : DataType data_type;
452 : GVariantIter iter;
453 : GVariant *variant;
454 :
455 4 : g_return_val_if_fail (array != NULL, FALSE);
456 4 : g_return_val_if_fail (builder != NULL, FALSE);
457 :
458 4 : g_variant_iter_init (&iter, array);
459 :
460 8 : while (g_variant_iter_next (&iter, "{&sv}", &name, &variant)) {
461 : /* Property interface.name */
462 4 : if (!property_to_attribute (name, interface, &attr_type, &data_type))
463 0 : return FALSE;
464 :
465 : /* Property value */
466 4 : if (!iter_get_variant (variant, data_type, attr_type, builder)) {
467 0 : g_variant_unref (variant);
468 0 : return FALSE;
469 : }
470 :
471 4 : g_variant_unref (variant);
472 : }
473 :
474 4 : return TRUE;
475 : }
476 :
477 : GVariant *
478 0 : gkd_secret_property_append_all (GckAttributes *attrs)
479 : {
480 : const GckAttribute *attr;
481 : DataType data_type;
482 : const gchar *name;
483 : gulong num, i;
484 : GVariantBuilder builder;
485 : GVariant *variant;
486 :
487 0 : g_return_val_if_fail (attrs, NULL);
488 :
489 0 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
490 0 : num = gck_attributes_count (attrs);
491 :
492 0 : for (i = 0; i < num; ++i) {
493 0 : attr = gck_attributes_at (attrs, i);
494 0 : if (!attribute_to_property (attr->type, &name, &data_type))
495 0 : g_return_val_if_reached (NULL);
496 :
497 0 : variant = iter_append_variant (data_type, attr);
498 0 : g_variant_builder_add (&builder, "{sv}", name, variant);
499 0 : g_variant_unref (variant);
500 : }
501 :
502 0 : return g_variant_builder_end (&builder);
503 : }
504 :
505 : GVariant *
506 49 : gkd_secret_property_append_variant (const GckAttribute *attr)
507 : {
508 : const gchar *property;
509 : DataType data_type;
510 :
511 49 : g_return_val_if_fail (attr, NULL);
512 :
513 49 : if (!attribute_to_property (attr->type, &property, &data_type))
514 0 : return NULL;
515 49 : return iter_append_variant (data_type, attr);
516 : }
517 :
518 : gboolean
519 2 : gkd_secret_property_parse_variant (GVariant *variant,
520 : const gchar *property,
521 : GckBuilder *builder)
522 : {
523 : CK_ATTRIBUTE_TYPE attr_type;
524 : DataType data_type;
525 :
526 2 : g_return_val_if_fail (variant, FALSE);
527 2 : g_return_val_if_fail (property, FALSE);
528 2 : g_return_val_if_fail (builder != NULL, FALSE);
529 :
530 2 : if (!property_to_attribute (property, NULL, &attr_type, &data_type))
531 0 : return FALSE;
532 :
533 2 : return iter_get_variant (variant, data_type, attr_type, builder);
534 : }
535 :
536 : gboolean
537 8 : gkd_secret_property_parse_fields (GVariant *variant,
538 : GckBuilder *builder)
539 : {
540 8 : g_return_val_if_fail (variant != NULL, FALSE);
541 8 : g_return_val_if_fail (builder != NULL, FALSE);
542 :
543 8 : return iter_get_fields (variant, CKA_G_FIELDS, builder);
544 : }
|