Branch data Line data Source code
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 : : GVariant *
23 : 90 : _secret_attributes_to_variant (GHashTable *attributes,
24 : : const gchar *schema_name)
25 : : {
26 : : GHashTableIter iter;
27 : : GVariantBuilder builder;
28 : : const gchar *name;
29 : : const gchar *value;
30 : :
31 [ - + ]: 90 : g_return_val_if_fail (attributes != NULL, NULL);
32 : :
33 : 90 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
34 : :
35 : 90 : g_hash_table_iter_init (&iter, attributes);
36 [ + + ]: 269 : while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&value)) {
37 [ + + + - ]: 179 : if (!schema_name || !g_str_equal (name, "xdg:schema"))
38 : 179 : g_variant_builder_add (&builder, "{ss}", name, value);
39 : : }
40 : :
41 [ + + ]: 90 : if (schema_name)
42 : 83 : g_variant_builder_add (&builder, "{ss}", "xdg:schema", schema_name);
43 : :
44 : 90 : return g_variant_builder_end (&builder);
45 : : }
46 : :
47 : : GHashTable *
48 : 8 : _secret_attributes_for_variant (GVariant *variant)
49 : : {
50 : : GVariantIter iter;
51 : : GHashTable *attributes;
52 : : gchar *value;
53 : : gchar *key;
54 : :
55 : 8 : attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
56 : :
57 : 8 : g_variant_iter_init (&iter, variant);
58 [ + + ]: 36 : while (g_variant_iter_next (&iter, "{ss}", &key, &value))
59 : 28 : g_hash_table_insert (attributes, key, value);
60 : :
61 : 8 : return attributes;
62 : : }
63 : :
64 : : /**
65 : : * secret_attributes_build: (skip)
66 : : * @schema: the schema for the attributes
67 : : * @...: the attribute keys and values, terminated with %NULL
68 : : *
69 : : * Build up a hash table of attribute values.
70 : : *
71 : : * The variable argument list should contain pairs of a) The attribute name as
72 : : * a null-terminated string, followed by b) attribute value, either a character
73 : : * string, an int number, or a gboolean value, as defined in the password
74 : : * @schema. The list of attributes should be terminated with a %NULL.
75 : : *
76 : : * Returns: (transfer full) (element-type utf8 utf8): a new table of
77 : : * attributes, to be released with [func@GLib.HashTable.unref]
78 : : */
79 : : GHashTable *
80 : 15 : secret_attributes_build (const SecretSchema *schema,
81 : : ...)
82 : : {
83 : : GHashTable *attributes;
84 : : va_list va;
85 : :
86 : 15 : va_start (va, schema);
87 : 15 : attributes = secret_attributes_buildv (schema, va);
88 : 15 : va_end (va);
89 : :
90 : 15 : return attributes;
91 : : }
92 : :
93 : : /**
94 : : * secret_attributes_buildv: (skip)
95 : : * @schema: the schema for the attributes
96 : : * @va: the attribute keys and values, terminated with %NULL
97 : : *
98 : : * Build up a hash table of attribute values.
99 : : *
100 : : * The variable argument list should contain pairs of a) The attribute name as
101 : : * a null-terminated string, followed by b) attribute value, either a character
102 : : * string, an int number, or a gboolean value, as defined in the password
103 : : * @schema. The list of attributes should be terminated with a %NULL.
104 : : *
105 : : * Returns: (transfer full) (element-type utf8 utf8): a new table of
106 : : * attributes, to be released with [func@GLib.HashTable.unref]
107 : : */
108 : : GHashTable *
109 : 37 : secret_attributes_buildv (const SecretSchema *schema,
110 : : va_list va)
111 : : {
112 : : const gchar *attribute_name;
113 : : SecretSchemaAttributeType type;
114 : : GHashTable *attributes;
115 : : const gchar *string;
116 : : gboolean type_found;
117 : 37 : gchar *value = NULL;
118 : : gboolean boolean;
119 : : gint integer;
120 : : gint i;
121 : :
122 [ - + ]: 37 : g_return_val_if_fail (schema != NULL, NULL);
123 : :
124 : 37 : attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
125 : :
126 : : for (;;) {
127 : 120 : attribute_name = va_arg (va, const gchar *);
128 [ + + ]: 120 : if (attribute_name == NULL)
129 : 37 : break;
130 : :
131 : 83 : type_found = FALSE;
132 [ + - ]: 160 : for (i = 0; i < G_N_ELEMENTS (schema->attributes); ++i) {
133 [ - + ]: 160 : if (!schema->attributes[i].name)
134 : 0 : break;
135 [ + + ]: 160 : if (g_str_equal (schema->attributes[i].name, attribute_name)) {
136 : 83 : type_found = TRUE;
137 : 83 : type = schema->attributes[i].type;
138 : 83 : break;
139 : : }
140 : : }
141 : :
142 [ - + ]: 83 : if (!type_found) {
143 : 0 : g_critical ("The attribute '%s' was not found in the password schema.", attribute_name);
144 : 0 : g_hash_table_unref (attributes);
145 : 0 : return NULL;
146 : : }
147 : :
148 [ + + + - ]: 83 : switch (type) {
149 : 24 : case SECRET_SCHEMA_ATTRIBUTE_BOOLEAN:
150 : 24 : boolean = va_arg (va, gboolean);
151 [ + + ]: 24 : value = g_strdup (boolean ? "true" : "false");
152 : 24 : break;
153 : 29 : case SECRET_SCHEMA_ATTRIBUTE_STRING:
154 : 29 : string = va_arg (va, gchar *);
155 [ - + ]: 29 : if (string == NULL) {
156 : 0 : g_critical ("The value for attribute '%s' was NULL", attribute_name);
157 : 0 : return NULL;
158 : : }
159 [ - + ]: 29 : if (!g_utf8_validate (string, -1, NULL)) {
160 : 0 : g_critical ("The value for attribute '%s' was not a valid UTF-8 string.", attribute_name);
161 : 0 : g_hash_table_unref (attributes);
162 : 0 : return NULL;
163 : : }
164 : 29 : value = g_strdup (string);
165 : 29 : break;
166 : 30 : case SECRET_SCHEMA_ATTRIBUTE_INTEGER:
167 : 30 : integer = va_arg (va, gint);
168 : 30 : value = g_strdup_printf ("%d", integer);
169 : 30 : break;
170 : 0 : default:
171 : 0 : g_critical ("The password attribute '%s' has an invalid type in the password schema.", attribute_name);
172 : 0 : g_hash_table_unref (attributes);
173 : 0 : return NULL;
174 : : }
175 : :
176 : 83 : g_hash_table_insert (attributes, g_strdup (attribute_name), value);
177 : : }
178 : :
179 : 37 : return attributes;
180 : : }
181 : :
182 : : /**
183 : : * secret_attributes_validate:
184 : : * @schema: the schema for the attributes
185 : : * @attributes: the attributes to be validated
186 : : * @error: place to report errors encountered
187 : : *
188 : : * Check if attributes are valid according to the provided schema.
189 : : *
190 : : * Verifies schema name if available, attribute names and parsing
191 : : * of attribute values.
192 : : *
193 : : * Returns: whether or not the given attributes table is valid
194 : : */
195 : : gboolean
196 : 181 : secret_attributes_validate (const SecretSchema *schema,
197 : : GHashTable *attributes,
198 : : GError **error)
199 : : {
200 : : const SecretSchemaAttribute *attribute;
201 : : GHashTableIter iter;
202 : 181 : gboolean any = FALSE;
203 : : gchar *key;
204 : : gchar *value;
205 : : gchar *end;
206 : : gint i;
207 : :
208 [ - + ]: 181 : g_return_val_if_fail (schema != NULL, FALSE);
209 : :
210 : 181 : g_hash_table_iter_init (&iter, attributes);
211 [ + + ]: 543 : while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value)) {
212 : 362 : any = TRUE;
213 : :
214 : : /* If the 'xdg:schema' meta-attribute is present,
215 : : ensure that it is consistent with the schema
216 : : name. */
217 [ + + ]: 362 : if (g_str_equal (key, "xdg:schema")) {
218 [ - + ]: 1 : if (!g_str_equal (value, schema->name)) {
219 : 0 : g_set_error_literal (error,
220 : : SECRET_ERROR,
221 : : SECRET_ERROR_MISMATCHED_SCHEMA,
222 : : "Schema attribute doesn't match schema name");
223 : 0 : return FALSE;
224 : : }
225 : 1 : continue;
226 : : }
227 : :
228 : : /* Pass through libgnomekeyring specific attributes */
229 [ + - - + : 361 : if (g_str_has_prefix (key, "gkr:"))
+ - + + ]
230 : 1 : continue;
231 : :
232 : : /* Find the attribute */
233 : 360 : attribute = NULL;
234 [ + - ]: 656 : for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++) {
235 [ - + ]: 656 : if (schema->attributes[i].name == NULL)
236 : 0 : break;
237 [ + + ]: 656 : if (g_str_equal (schema->attributes[i].name, key)) {
238 : 360 : attribute = &schema->attributes[i];
239 : 360 : break;
240 : : }
241 : : }
242 : :
243 [ - + ]: 360 : if (attribute == NULL) {
244 : 0 : g_set_error (error,
245 : : SECRET_ERROR,
246 : : SECRET_ERROR_NO_MATCHING_ATTRIBUTE,
247 : : "Schema does not contain any attributes matching %s",
248 : : key);
249 : 0 : return FALSE;
250 : : }
251 : :
252 [ + + + - ]: 360 : switch (attribute->type) {
253 : 91 : case SECRET_SCHEMA_ATTRIBUTE_BOOLEAN:
254 [ + + - + ]: 91 : if (!g_str_equal (value, "true") && !g_str_equal (value, "false")) {
255 : 0 : g_set_error (error,
256 : : SECRET_ERROR,
257 : : SECRET_ERROR_WRONG_TYPE,
258 : : "Attribute %s could not be parsed into a boolean",
259 : : key);
260 : 0 : return FALSE;
261 : : }
262 : 91 : break;
263 : 157 : case SECRET_SCHEMA_ATTRIBUTE_INTEGER:
264 : 157 : end = NULL;
265 : 157 : g_ascii_strtoll (value, &end, 10);
266 [ + - - + ]: 157 : if (!end || end[0] != '\0') {
267 : 0 : g_set_error (error,
268 : : SECRET_ERROR,
269 : : SECRET_ERROR_WRONG_TYPE,
270 : : "Attribute %s could not be parsed into an integer",
271 : : key);
272 : 0 : return FALSE;
273 : : }
274 : 157 : break;
275 : 112 : case SECRET_SCHEMA_ATTRIBUTE_STRING:
276 [ - + ]: 112 : if (!g_utf8_validate (value, -1, NULL)) {
277 : 0 : g_set_error (error,
278 : : SECRET_ERROR,
279 : : SECRET_ERROR_WRONG_TYPE,
280 : : "Attribute %s could not be parsed into a string",
281 : : key);
282 : 0 : return FALSE;
283 : : }
284 : 112 : break;
285 : 0 : default:
286 : 0 : g_set_error (error,
287 : : SECRET_ERROR,
288 : : SECRET_ERROR_WRONG_TYPE,
289 : : "%s: Invalid attribute type",
290 : : key);
291 : 0 : return FALSE;
292 : : }
293 : : }
294 : :
295 : : /* Nothing to match on, resulting search would match everything :S */
296 [ + + + + ]: 181 : if (!any && schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME) {
297 : 1 : g_set_error_literal (error,
298 : : SECRET_ERROR,
299 : : SECRET_ERROR_EMPTY_TABLE,
300 : : "Must have at least one attribute to check");
301 : 1 : return FALSE;
302 : : }
303 : :
304 : 180 : return TRUE;
305 : : }
306 : :
307 : : // Private function to be used internally
308 : : gboolean
309 : 181 : _secret_attributes_validate (const SecretSchema *schema,
310 : : GHashTable *attributes,
311 : : const char *pretty_function,
312 : : gboolean matching)
313 : : {
314 : 181 : GError *error = NULL;
315 : :
316 [ + + ]: 181 : if (!secret_attributes_validate (schema, attributes, &error)) {
317 : : // if matching is false, an empty table is fine
318 [ + - + - ]: 1 : if ((!matching) && (error->code == SECRET_ERROR_EMPTY_TABLE)) {
319 : 1 : g_error_free (error);
320 : 1 : return TRUE;
321 : : }
322 : :
323 : 0 : g_warning ("%s: error validating schema: %s", pretty_function, error->message);
324 : 0 : g_error_free (error);
325 : 0 : return FALSE;
326 : : }
327 : 180 : return TRUE;
328 : : }
329 : :
330 : :
331 : : GHashTable *
332 : 0 : _secret_attributes_copy (GHashTable *attributes)
333 : : {
334 : : GHashTableIter iter;
335 : : GHashTable *copy;
336 : : gchar *key;
337 : : gchar *value;
338 : :
339 [ # # ]: 0 : if (attributes == NULL)
340 : 0 : return NULL;
341 : :
342 : 0 : copy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
343 : :
344 : 0 : g_hash_table_iter_init (&iter, attributes);
345 [ # # ]: 0 : while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
346 : 0 : g_hash_table_insert (copy, g_strdup (key), g_strdup (value));
347 : :
348 : 0 : return copy;
349 : : }
|