Update documentation for to have correct headers
[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_warning ("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 (!g_utf8_validate (string, -1, NULL)) {
169                                 g_warning ("The value for attribute '%s' was not a valid utf-8 string.", attribute_name);
170                                 g_hash_table_unref (attributes);
171                                 return NULL;
172                         }
173                         value = g_strdup (string);
174                         break;
175                 case SECRET_SCHEMA_ATTRIBUTE_INTEGER:
176                         integer = va_arg (va, gint);
177                         value = g_strdup_printf ("%d", integer);
178                         break;
179                 default:
180                         g_warning ("The password attribute '%s' has an invalid type in the password schema.", attribute_name);
181                         g_hash_table_unref (attributes);
182                         return NULL;
183                 }
184
185                 g_hash_table_insert (attributes, g_strdup (attribute_name), value);
186         }
187
188         return attributes;
189 }
190
191 gboolean
192 _secret_attributes_validate (const SecretSchema *schema,
193                              GHashTable *attributes,
194                              const char *pretty_function,
195                              gboolean matching)
196 {
197         const SecretSchemaAttribute *attribute;
198         GHashTableIter iter;
199         gboolean any;
200         gchar *key;
201         gchar *value;
202         gchar *end;
203         gint i;
204
205         g_return_val_if_fail (schema != NULL, FALSE);
206
207         g_hash_table_iter_init (&iter, attributes);
208         while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value)) {
209                 any = TRUE;
210
211                 /* Find the attribute */
212                 attribute = NULL;
213                 for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++) {
214                         if (schema->attributes[i].name == NULL)
215                                 break;
216                         if (g_str_equal (schema->attributes[i].name, key)) {
217                                 attribute = &schema->attributes[i];
218                                 break;
219                         }
220                 }
221
222                 if (attribute == NULL) {
223                         g_critical ("%s: invalid %s attribute in for %s schema",
224                                     pretty_function, key, schema->name);
225                         return FALSE;
226                 }
227
228                 switch (attribute->type) {
229                 case SECRET_SCHEMA_ATTRIBUTE_BOOLEAN:
230                         if (!g_str_equal (value, "true") && !g_str_equal (value, "false")) {
231                                 g_critical ("%s: invalid %s boolean value for %s schema: %s",
232                                             pretty_function, key, schema->name, value);
233                                 return FALSE;
234                         }
235                         break;
236                 case SECRET_SCHEMA_ATTRIBUTE_INTEGER:
237                         end = NULL;
238                         g_ascii_strtoll (value, &end, 10);
239                         if (!end || end[0] != '\0') {
240                                 g_warning ("%s: invalid %s integer value for %s schema: %s",
241                                            pretty_function, key, schema->name, value);
242                                 return FALSE;
243                         }
244                         break;
245                 case SECRET_SCHEMA_ATTRIBUTE_STRING:
246                         if (!g_utf8_validate (value, -1, NULL)) {
247                                 g_warning ("%s: invalid %s string value for %s schema: %s",
248                                            pretty_function, key, schema->name, value);
249                                 return FALSE;
250                         }
251                         break;
252                 default:
253                         g_warning ("%s: invalid %s value type in %s schema",
254                                    pretty_function, key, schema->name);
255                         return FALSE;
256                 }
257         }
258
259         /* Nothing to match on, resulting search would match everything :S */
260         if (matching && !any && schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME) {
261                 g_warning ("%s: must specify at least one attribute to match",
262                            pretty_function);
263                 return FALSE;
264         }
265
266         return TRUE;
267 }
268
269 GHashTable *
270 _secret_attributes_copy (GHashTable *attributes)
271 {
272         GHashTableIter iter;
273         GHashTable *copy;
274         gchar *key;
275         gchar *value;
276
277         if (attributes == NULL)
278                 return NULL;
279
280         copy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
281
282         g_hash_table_iter_init (&iter, attributes);
283         while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
284                 g_hash_table_insert (copy, g_strdup (key), g_strdup (value));
285
286         return copy;
287 }