2012-06-28 11:15:06 +00:00
|
|
|
/* libsecret - GLib wrapper for Secret Service
|
|
|
|
*
|
|
|
|
* Copyright 2011 Collabora Ltd.
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Lesser General Public License as published
|
|
|
|
* by the Free Software Foundation; either version 2.1 of the licence or (at
|
|
|
|
* your option) any later version.
|
|
|
|
*
|
|
|
|
* See the included COPYING file for more information.
|
|
|
|
*
|
|
|
|
* Author: Stef Walter <stefw@gnome.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "secret-attributes.h"
|
|
|
|
#include "secret-private.h"
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION:secret-attributes
|
|
|
|
* @title: Secret Attributes
|
|
|
|
* @short_description: secret attributes
|
|
|
|
*
|
|
|
|
* Each item has a set of attributes, which are used to locate the item later.
|
|
|
|
* These are not stored or transferred in a secure manner. Each attribute has
|
|
|
|
* a string name and a string value. These attributes are represented by a
|
|
|
|
* #GHashTable with string keys and values.
|
|
|
|
*
|
|
|
|
* Use secret_attributes_build() to simply build up a set of attributes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
GVariant *
|
|
|
|
_secret_attributes_to_variant (GHashTable *attributes,
|
|
|
|
const gchar *schema_name)
|
|
|
|
{
|
|
|
|
GHashTableIter iter;
|
|
|
|
GVariantBuilder builder;
|
|
|
|
const gchar *name;
|
|
|
|
const gchar *value;
|
|
|
|
|
|
|
|
g_return_val_if_fail (attributes != NULL, NULL);
|
|
|
|
|
|
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, attributes);
|
|
|
|
while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&value)) {
|
|
|
|
if (!schema_name || !g_str_equal (name, "xdg:schema"))
|
|
|
|
g_variant_builder_add (&builder, "{ss}", name, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (schema_name)
|
|
|
|
g_variant_builder_add (&builder, "{ss}", "xdg:schema", schema_name);
|
|
|
|
|
|
|
|
return g_variant_builder_end (&builder);
|
|
|
|
}
|
|
|
|
|
|
|
|
GHashTable *
|
|
|
|
_secret_attributes_for_variant (GVariant *variant)
|
|
|
|
{
|
|
|
|
GVariantIter iter;
|
|
|
|
GHashTable *attributes;
|
|
|
|
gchar *value;
|
|
|
|
gchar *key;
|
|
|
|
|
|
|
|
attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
|
|
|
|
|
g_variant_iter_init (&iter, variant);
|
|
|
|
while (g_variant_iter_next (&iter, "{ss}", &key, &value))
|
|
|
|
g_hash_table_insert (attributes, key, value);
|
|
|
|
|
|
|
|
return attributes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* secret_attributes_build: (skip)
|
|
|
|
* @schema: the schema for the attributes
|
|
|
|
* @...: the attribute keys and values, terminated with %NULL
|
|
|
|
*
|
|
|
|
* Build up a hash table of attribute values.
|
|
|
|
*
|
|
|
|
* The variable argument list should contain pairs of a) The attribute name as
|
|
|
|
* a null-terminated string, followed by b) attribute value, either a character
|
|
|
|
* string, an int number, or a gboolean value, as defined in the password
|
|
|
|
* @schema. The list of attribtues should be terminated with a %NULL.
|
|
|
|
*
|
2012-07-10 20:02:19 +00:00
|
|
|
* Returns: (transfer full) (element-type utf8 utf8): a new table of
|
|
|
|
* attributes, to be released with g_hash_table_unref()
|
2012-06-28 11:15:06 +00:00
|
|
|
*/
|
|
|
|
GHashTable *
|
|
|
|
secret_attributes_build (const SecretSchema *schema,
|
|
|
|
...)
|
|
|
|
{
|
|
|
|
GHashTable *attributes;
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
va_start (va, schema);
|
|
|
|
attributes = secret_attributes_buildv (schema, va);
|
|
|
|
va_end (va);
|
|
|
|
|
|
|
|
return attributes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* secret_attributes_buildv: (skip)
|
|
|
|
* @schema: the schema for the attributes
|
|
|
|
* @va: the attribute keys and values, terminated with %NULL
|
|
|
|
*
|
|
|
|
* Build up a hash table of attribute values.
|
|
|
|
*
|
|
|
|
* The variable argument list should contain pairs of a) The attribute name as
|
|
|
|
* a null-terminated string, followed by b) attribute value, either a character
|
|
|
|
* string, an int number, or a gboolean value, as defined in the password
|
|
|
|
* @schema. The list of attribtues should be terminated with a %NULL.
|
|
|
|
*
|
2012-07-10 20:02:19 +00:00
|
|
|
* Returns: (transfer full) (element-type utf8 utf8): a new table of
|
|
|
|
* attributes, to be released with g_hash_table_unref()
|
2012-06-28 11:15:06 +00:00
|
|
|
*/
|
|
|
|
GHashTable *
|
|
|
|
secret_attributes_buildv (const SecretSchema *schema,
|
|
|
|
va_list va)
|
|
|
|
{
|
|
|
|
const gchar *attribute_name;
|
|
|
|
SecretSchemaAttributeType type;
|
|
|
|
GHashTable *attributes;
|
|
|
|
const gchar *string;
|
|
|
|
gboolean type_found;
|
|
|
|
gchar *value = NULL;
|
|
|
|
gboolean boolean;
|
|
|
|
gint integer;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_return_val_if_fail (schema != NULL, NULL);
|
|
|
|
|
|
|
|
attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
attribute_name = va_arg (va, const gchar *);
|
|
|
|
if (attribute_name == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
type_found = FALSE;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (schema->attributes); ++i) {
|
|
|
|
if (!schema->attributes[i].name)
|
|
|
|
break;
|
|
|
|
if (g_str_equal (schema->attributes[i].name, attribute_name)) {
|
|
|
|
type_found = TRUE;
|
|
|
|
type = schema->attributes[i].type;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!type_found) {
|
|
|
|
g_warning ("The attribute '%s' was not found in the password schema.", attribute_name);
|
|
|
|
g_hash_table_unref (attributes);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case SECRET_SCHEMA_ATTRIBUTE_BOOLEAN:
|
|
|
|
boolean = va_arg (va, gboolean);
|
|
|
|
value = g_strdup (boolean ? "true" : "false");
|
|
|
|
break;
|
|
|
|
case SECRET_SCHEMA_ATTRIBUTE_STRING:
|
|
|
|
string = va_arg (va, gchar *);
|
|
|
|
if (!g_utf8_validate (string, -1, NULL)) {
|
|
|
|
g_warning ("The value for attribute '%s' was not a valid utf-8 string.", attribute_name);
|
|
|
|
g_hash_table_unref (attributes);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
value = g_strdup (string);
|
|
|
|
break;
|
|
|
|
case SECRET_SCHEMA_ATTRIBUTE_INTEGER:
|
|
|
|
integer = va_arg (va, gint);
|
|
|
|
value = g_strdup_printf ("%d", integer);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_warning ("The password attribute '%s' has an invalid type in the password schema.", attribute_name);
|
|
|
|
g_hash_table_unref (attributes);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_hash_table_insert (attributes, g_strdup (attribute_name), value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return attributes;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
_secret_attributes_validate (const SecretSchema *schema,
|
2012-07-10 19:37:20 +00:00
|
|
|
GHashTable *attributes,
|
|
|
|
const char *pretty_function,
|
|
|
|
gboolean matching)
|
2012-06-28 11:15:06 +00:00
|
|
|
{
|
|
|
|
const SecretSchemaAttribute *attribute;
|
|
|
|
GHashTableIter iter;
|
2012-07-10 19:37:20 +00:00
|
|
|
gboolean any;
|
2012-06-28 11:15:06 +00:00
|
|
|
gchar *key;
|
|
|
|
gchar *value;
|
|
|
|
gchar *end;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_return_val_if_fail (schema != NULL, FALSE);
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, attributes);
|
|
|
|
while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value)) {
|
2012-07-10 19:37:20 +00:00
|
|
|
any = TRUE;
|
2012-06-28 11:15:06 +00:00
|
|
|
|
|
|
|
/* Find the attribute */
|
|
|
|
attribute = NULL;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++) {
|
|
|
|
if (schema->attributes[i].name == NULL)
|
|
|
|
break;
|
|
|
|
if (g_str_equal (schema->attributes[i].name, key)) {
|
|
|
|
attribute = &schema->attributes[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attribute == NULL) {
|
2012-07-10 19:37:20 +00:00
|
|
|
g_critical ("%s: invalid %s attribute in for %s schema",
|
|
|
|
pretty_function, key, schema->name);
|
2012-06-28 11:15:06 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (attribute->type) {
|
|
|
|
case SECRET_SCHEMA_ATTRIBUTE_BOOLEAN:
|
|
|
|
if (!g_str_equal (value, "true") && !g_str_equal (value, "false")) {
|
2012-07-10 19:37:20 +00:00
|
|
|
g_critical ("%s: invalid %s boolean value for %s schema: %s",
|
|
|
|
pretty_function, key, schema->name, value);
|
2012-06-28 11:15:06 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SECRET_SCHEMA_ATTRIBUTE_INTEGER:
|
|
|
|
end = NULL;
|
|
|
|
g_ascii_strtoll (value, &end, 10);
|
|
|
|
if (!end || end[0] != '\0') {
|
2012-07-10 19:37:20 +00:00
|
|
|
g_warning ("%s: invalid %s integer value for %s schema: %s",
|
|
|
|
pretty_function, key, schema->name, value);
|
2012-06-28 11:15:06 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SECRET_SCHEMA_ATTRIBUTE_STRING:
|
|
|
|
if (!g_utf8_validate (value, -1, NULL)) {
|
2012-07-10 19:37:20 +00:00
|
|
|
g_warning ("%s: invalid %s string value for %s schema: %s",
|
|
|
|
pretty_function, key, schema->name, value);
|
2012-06-28 11:15:06 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2012-07-10 19:37:20 +00:00
|
|
|
g_warning ("%s: invalid %s value type in %s schema",
|
|
|
|
pretty_function, key, schema->name);
|
2012-06-28 11:15:06 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-10 19:37:20 +00:00
|
|
|
/* Nothing to match on, resulting search would match everything :S */
|
|
|
|
if (matching && !any && schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME) {
|
|
|
|
g_warning ("%s: must specify at least one attribute to match",
|
|
|
|
pretty_function);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-06-28 11:15:06 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GHashTable *
|
|
|
|
_secret_attributes_copy (GHashTable *attributes)
|
|
|
|
{
|
|
|
|
GHashTableIter iter;
|
|
|
|
GHashTable *copy;
|
|
|
|
gchar *key;
|
|
|
|
gchar *value;
|
|
|
|
|
|
|
|
if (attributes == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
copy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, attributes);
|
|
|
|
while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
|
|
|
|
g_hash_table_insert (copy, g_strdup (key), g_strdup (value));
|
|
|
|
|
|
|
|
return copy;
|
|
|
|
}
|