Share the memory pool with the gcr or libgnome-keyring library.
[platform/upstream/libsecret.git] / libsecret / secret-attributes.c
1 /* libsecret - GLib wrapper for Secret Service
2  *
3  * Copyright 2011 Collabora Ltd.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published
7  * by the Free Software Foundation; either version 2.1 of the licence or (at
8  * your option) any later version.
9  *
10  * See the included COPYING file for more information.
11  *
12  * Author: Stef Walter <stefw@gnome.org>
13  */
14
15 #include "config.h"
16
17 #include "secret-attributes.h"
18 #include "secret-private.h"
19
20 #include <string.h>
21
22 /**
23  * SECTION:secret-attributes
24  * @title: Secret Attributes
25  * @short_description: secret attributes
26  *
27  * Each item has a set of attributes, which are used to locate the item later.
28  * These are not stored or transferred in a secure manner. Each attribute has
29  * a string name and a string value. These attributes are represented by a
30  * #GHashTable with string keys and values.
31  *
32  * Use secret_attributes_build() to simply build up a set of attributes.
33  */
34
35 GVariant *
36 _secret_attributes_to_variant (GHashTable *attributes,
37                                const gchar *schema_name)
38 {
39         GHashTableIter iter;
40         GVariantBuilder builder;
41         const gchar *name;
42         const gchar *value;
43
44         g_return_val_if_fail (attributes != NULL, NULL);
45
46         g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
47
48         g_hash_table_iter_init (&iter, attributes);
49         while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&value)) {
50                 if (!schema_name || !g_str_equal (name, "xdg:schema"))
51                         g_variant_builder_add (&builder, "{ss}", name, value);
52         }
53
54         if (schema_name)
55                 g_variant_builder_add (&builder, "{ss}", "xdg:schema", schema_name);
56
57         return g_variant_builder_end (&builder);
58 }
59
60 GHashTable *
61 _secret_attributes_for_variant (GVariant *variant)
62 {
63         GVariantIter iter;
64         GHashTable *attributes;
65         gchar *value;
66         gchar *key;
67
68         attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
69
70         g_variant_iter_init (&iter, variant);
71         while (g_variant_iter_next (&iter, "{ss}", &key, &value))
72                 g_hash_table_insert (attributes, key, value);
73
74         return attributes;
75 }
76
77 /**
78  * secret_attributes_build: (skip)
79  * @schema: the schema for the attributes
80  * @...: the attribute keys and values, terminated with %NULL
81  *
82  * Build up a hash table of attribute values.
83  *
84  * The variable argument list should contain pairs of a) The attribute name as
85  * a null-terminated string, followed by b) attribute value, either a character
86  * string, an int number, or a gboolean value, as defined in the password
87  * @schema. The list of attribtues should be terminated with a %NULL.
88  *
89  * Returns: (transfer full) (element-type utf8 utf8): a new table of
90  *          attributes, to be released with g_hash_table_unref()
91  */
92 GHashTable *
93 secret_attributes_build (const SecretSchema *schema,
94                          ...)
95 {
96         GHashTable *attributes;
97         va_list va;
98
99         va_start (va, schema);
100         attributes = secret_attributes_buildv (schema, va);
101         va_end (va);
102
103         return attributes;
104 }
105
106 /**
107  * secret_attributes_buildv: (skip)
108  * @schema: the schema for the attributes
109  * @va: the attribute keys and values, terminated with %NULL
110  *
111  * Build up a hash table of attribute values.
112  *
113  * The variable argument list should contain pairs of a) The attribute name as
114  * a null-terminated string, followed by b) attribute value, either a character
115  * string, an int number, or a gboolean value, as defined in the password
116  * @schema. The list of attribtues should be terminated with a %NULL.
117  *
118  * Returns: (transfer full) (element-type utf8 utf8): a new table of
119  *          attributes, to be released with g_hash_table_unref()
120  */
121 GHashTable *
122 secret_attributes_buildv (const SecretSchema *schema,
123                           va_list va)
124 {
125         const gchar *attribute_name;
126         SecretSchemaAttributeType type;
127         GHashTable *attributes;
128         const gchar *string;
129         gboolean type_found;
130         gchar *value = NULL;
131         gboolean boolean;
132         gint integer;
133         gint i;
134
135         g_return_val_if_fail (schema != NULL, NULL);
136
137         attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
138
139         for (;;) {
140                 attribute_name = va_arg (va, const gchar *);
141                 if (attribute_name == NULL)
142                         break;
143
144                 type_found = FALSE;
145                 for (i = 0; i < G_N_ELEMENTS (schema->attributes); ++i) {
146                         if (!schema->attributes[i].name)
147                                 break;
148                         if (g_str_equal (schema->attributes[i].name, attribute_name)) {
149                                 type_found = TRUE;
150                                 type = schema->attributes[i].type;
151                                 break;
152                         }
153                 }
154
155                 if (!type_found) {
156                         g_critical ("The attribute '%s' was not found in the password schema.", attribute_name);
157                         g_hash_table_unref (attributes);
158                         return NULL;
159                 }
160
161                 switch (type) {
162                 case SECRET_SCHEMA_ATTRIBUTE_BOOLEAN:
163                         boolean = va_arg (va, gboolean);
164                         value = g_strdup (boolean ? "true" : "false");
165                         break;
166                 case SECRET_SCHEMA_ATTRIBUTE_STRING:
167                         string = va_arg (va, gchar *);
168                         if (string == NULL) {
169                                 g_critical ("The value for attribute '%s' was NULL", attribute_name);
170                                 return NULL;
171                         }
172                         if (!g_utf8_validate (string, -1, NULL)) {
173                                 g_critical ("The value for attribute '%s' was not a valid UTF-8 string.", attribute_name);
174                                 g_hash_table_unref (attributes);
175                                 return NULL;
176                         }
177                         value = g_strdup (string);
178                         break;
179                 case SECRET_SCHEMA_ATTRIBUTE_INTEGER:
180                         integer = va_arg (va, gint);
181                         value = g_strdup_printf ("%d", integer);
182                         break;
183                 default:
184                         g_critical ("The password attribute '%s' has an invalid type in the password schema.", attribute_name);
185                         g_hash_table_unref (attributes);
186                         return NULL;
187                 }
188
189                 g_hash_table_insert (attributes, g_strdup (attribute_name), value);
190         }
191
192         return attributes;
193 }
194
195 gboolean
196 _secret_attributes_validate (const SecretSchema *schema,
197                              GHashTable *attributes,
198                              const char *pretty_function,
199                              gboolean matching)
200 {
201         const SecretSchemaAttribute *attribute;
202         GHashTableIter iter;
203         gboolean any;
204         gchar *key;
205         gchar *value;
206         gchar *end;
207         gint i;
208
209         g_return_val_if_fail (schema != NULL, FALSE);
210
211         g_hash_table_iter_init (&iter, attributes);
212         while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value)) {
213                 any = TRUE;
214
215                 /* Find the attribute */
216                 attribute = NULL;
217                 for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++) {
218                         if (schema->attributes[i].name == NULL)
219                                 break;
220                         if (g_str_equal (schema->attributes[i].name, key)) {
221                                 attribute = &schema->attributes[i];
222                                 break;
223                         }
224                 }
225
226                 if (attribute == NULL) {
227                         g_critical ("%s: invalid %s attribute for %s schema",
228                                     pretty_function, key, schema->name);
229                         return FALSE;
230                 }
231
232                 switch (attribute->type) {
233                 case SECRET_SCHEMA_ATTRIBUTE_BOOLEAN:
234                         if (!g_str_equal (value, "true") && !g_str_equal (value, "false")) {
235                                 g_critical ("%s: invalid %s boolean value for %s schema: %s",
236                                             pretty_function, key, schema->name, value);
237                                 return FALSE;
238                         }
239                         break;
240                 case SECRET_SCHEMA_ATTRIBUTE_INTEGER:
241                         end = NULL;
242                         g_ascii_strtoll (value, &end, 10);
243                         if (!end || end[0] != '\0') {
244                                 g_warning ("%s: invalid %s integer value for %s schema: %s",
245                                            pretty_function, key, schema->name, value);
246                                 return FALSE;
247                         }
248                         break;
249                 case SECRET_SCHEMA_ATTRIBUTE_STRING:
250                         if (!g_utf8_validate (value, -1, NULL)) {
251                                 g_warning ("%s: invalid %s string value for %s schema: %s",
252                                            pretty_function, key, schema->name, value);
253                                 return FALSE;
254                         }
255                         break;
256                 default:
257                         g_warning ("%s: invalid %s value type in %s schema",
258                                    pretty_function, key, schema->name);
259                         return FALSE;
260                 }
261         }
262
263         /* Nothing to match on, resulting search would match everything :S */
264         if (matching && !any && schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME) {
265                 g_warning ("%s: must specify at least one attribute to match",
266                            pretty_function);
267                 return FALSE;
268         }
269
270         return TRUE;
271 }
272
273 GHashTable *
274 _secret_attributes_copy (GHashTable *attributes)
275 {
276         GHashTableIter iter;
277         GHashTable *copy;
278         gchar *key;
279         gchar *value;
280
281         if (attributes == NULL)
282                 return NULL;
283
284         copy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
285
286         g_hash_table_iter_init (&iter, attributes);
287         while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
288                 g_hash_table_insert (copy, g_strdup (key), g_strdup (value));
289
290         return copy;
291 }