libsecret/library/secret-schema.c

384 lines
12 KiB
C

/* 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-enum-types.h"
#include "secret-password.h"
#include "secret-private.h"
#include "secret-value.h"
#include <egg/egg-secure-memory.h>
/**
* SECTION:secret-schema
* @title: SecretSchema
* @short_description: Schema for defining which attributes are on items
*
* Each password is associated with a set of attributes. Attribute values can
* be either strings, integers or booleans.
*
* The names and types of allowed attributes for a given password are defined
* with a schema.
*
* Additional schemas can be defined via the %SecretSchema structure like this:
*
* <informalexample><programlisting language="c">
* /<!-- -->* in a header: *<!-- -->/
*
* const SecretSchema * example_get_schema (void) G_GNUC_CONST;
*
* #define EXAMPLE_SCHEMA example_get_schema ()
*
*
* /<!-- -->* in a .c file: *<!-- -->/
*
* const SecretSchema *
* example_get_schema (void)
* {
* static const SecretSchema the_schema = {
* "org.example.Password", SECRET_SCHEMA_NONE,
* {
* { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER },
* { "string", SECRET_SCHEMA_ATTRIBUTE_STRING },
* { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN },
* { "NULL", 0 },
* }
* };
* return &the_schema;
* }
* </programlisting></informalexample>
*
* Stability: Stable
*/
/**
* SecretSchema:
* @name: the dotted name of the schema
* @flags: flags for the schema
* @attributes: the attribute names and types of those attributes
*
* Represents a set of attributes that are stored with an item. These schemas
* are used for interoperability between various services storing the same types
* of items.
*
* Each schema has a name like "org.gnome.keyring.NetworkPassword", and defines
* a set of attributes, and types (string, integer, boolean) for those attributes.
*
* Attributes are stored as strings in the Secret Service, and the attribute
* types simply define standard ways to store integer and boolean values as strings.
* Attributes are represented in libsecret via a #GHashTable with string keys and
* values. Even for values that defined as an integer or boolean in the schema,
* the attribute values in the #GHashTable are strings. Boolean values are stored
* as the strings 'true' and 'false'. Integer values are stored in decimal, with
* a preceeding negative sign for negative integers.
*
* Schemas are handled entirely on the client side by this library. The name of the
* schema is automatically stored as an attribute on the item.
*
* Normally when looking up passwords only those with matching schema names are
* returned. If the schema @flags contain the %SECRET_SCHEMA_DONT_MATCH_NAME flag,
* then lookups will not check that the schema name matches that on the item, only
* the schema's attributes are matched. This is useful when you are looking up items
* that are not stored by the libsecret library. Other libraries such as libgnome-keyring
* don't store the schema name.
*
* Stability: Stable
*/
/**
* SecretSchemaFlags:
* @SECRET_SCHEMA_NONE: no flags for the schema
* @SECRET_SCHEMA_DONT_MATCH_NAME: don't match the schema name when looking up or
* removing passwords
*
* Flags for a #SecretSchema definition.
*/
/**
* SecretSchemaAttribute:
* @name: name of the attribute
* @type: the type of the attribute
*
* An attribute in a #SecretSchema.
*/
/**
* SecretSchemaAttributeType:
* @SECRET_SCHEMA_ATTRIBUTE_BOOLEAN: a boolean attribute, stored as 'true' or 'false'
* @SECRET_SCHEMA_ATTRIBUTE_INTEGER: an integer attribute, stored as a decimal
* @SECRET_SCHEMA_ATTRIBUTE_STRING: a utf-8 string attribute
*
* The type of an attribute in a #SecretSchema. Attributes are stored as strings
* in the Secret Service, and the attribute types simply define standard ways
* to store integer and boolean values as strings.
*/
static SecretSchemaAttribute *
schema_attribute_copy (SecretSchemaAttribute *attribute)
{
SecretSchemaAttribute *copy;
copy = g_slice_new0 (SecretSchemaAttribute);
copy->name = g_strdup (attribute->name);
copy->type = attribute->type;
return copy;
}
static void
schema_attribute_free (SecretSchemaAttribute *attribute)
{
g_free ((gchar *)attribute->name);
g_slice_free (SecretSchemaAttribute, attribute);
}
G_DEFINE_BOXED_TYPE (SecretSchemaAttribute, secret_schema_attribute,
schema_attribute_copy, schema_attribute_free);
/**
* secret_schema_newv:
* @name: the dotted name of the schema
* @flags: the flags for the schema
* @attribute_names_and_types: (element-type utf8 Secret.SchemaAttributeType): the attribute names and types of those attributes
*
* Using this function is not normally necessary from C code. This is useful
* for constructing #SecretSchema structures in bindings.
*
* A schema represents a set of attributes that are stored with an item. These
* schemas are used for interoperability between various services storing the
* same types of items.
*
* Each schema has an @name like "org.gnome.keyring.NetworkPassword", and
* defines a set of attributes names, and types (string, integer, boolean) for
* those attributes.
*
* Each key in the @attributes table should be a attribute name strings, and
* the values in the table should be integers from the #SecretSchemaAttributeType
* enumeration, representing the attribute type for each attribute name.
*
* Normally when looking up passwords only those with matching schema names are
* returned. If the schema @flags contain the %SECRET_SCHEMA_DONT_MATCH_NAME flag,
* then lookups will not check that the schema name matches that on the item, only
* the schema's attributes are matched. This is useful when you are looking up items
* that are not stored by the libsecret library. Other libraries such as libgnome-keyring
* don't store the schema name.
*
* Rename to: secret_schema_new
*
* Returns: (transfer full): the new schema, which should be unreferenced with
* secret_schema_unref() when done
*/
SecretSchema *
secret_schema_newv (const gchar *name,
SecretSchemaFlags flags,
GHashTable *attribute_names_and_types)
{
SecretSchema *schema;
GHashTableIter iter;
GEnumClass *enumc;
gpointer value;
gpointer key;
gint type;
gint ind = 0;
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (attribute_names_and_types != NULL, NULL);
schema = g_slice_new0 (SecretSchema);
schema->name = g_strdup (name);
schema->flags = flags;
schema->reserved = 1;
if (attribute_names_and_types) {
g_hash_table_iter_init (&iter, attribute_names_and_types);
while (g_hash_table_iter_next (&iter, &key, &value)) {
if (ind >= G_N_ELEMENTS (schema->attributes)) {
g_warning ("too many attributes for schema, max %d",
(gint) G_N_ELEMENTS (schema->attributes));
break;
}
type = GPOINTER_TO_INT (value);
enumc = G_ENUM_CLASS (g_type_class_ref (SECRET_TYPE_SCHEMA_ATTRIBUTE_TYPE));
if (!g_enum_get_value (enumc, type)) {
g_warning ("invalid type for attribute %s", (gchar *)key);
type = -1;
}
g_type_class_unref (enumc);
if (type >= 0) {
schema->attributes[ind].name = g_strdup (key);
schema->attributes[ind].type = type;
}
ind++;
}
}
return schema;
}
/**
* secret_schema_new: (skip)
* @name: the dotted name of the schema
* @flags: the flags for the schema
* @...: the attribute names and types, terminated with %NULL
*
* Using this function is not normally necessary from C code.
*
* A schema represents a set of attributes that are stored with an item. These
* schemas are used for interoperability between various services storing the
* same types of items.
*
* Each schema has an @name like "org.gnome.keyring.NetworkPassword", and
* defines a set of attributes names, and types (string, integer, boolean) for
* those attributes.
*
* The variable argument list should contain pairs of a) The attribute name as
* a null-terminated string, followed by b) integers from the
* #SecretSchemaAttributeType enumeration, representing the attribute type for
* each attribute name. The list of attribtues should be terminated with a %NULL.
*
* Normally when looking up passwords only those with matching schema names are
* returned. If the schema @flags contain the %SECRET_SCHEMA_DONT_MATCH_NAME flag,
* then lookups will not check that the schema name matches that on the item, only
* the schema's attributes are matched. This is useful when you are looking up items
* that are not stored by the libsecret library. Other libraries such as libgnome-keyring
* don't store the schema name.
*
* Returns: (transfer full): the new schema, which should be unreferenced with
* secret_schema_unref() when done
*/
SecretSchema *
secret_schema_new (const gchar *name,
SecretSchemaFlags flags,
...)
{
SecretSchemaAttributeType type;
GHashTable *attributes;
SecretSchema *schema;
const gchar *attribute;
va_list va;
g_return_val_if_fail (name != NULL, NULL);
va_start (va, flags);
attributes = g_hash_table_new (g_str_hash, g_str_equal);
while ((attribute = va_arg (va, const gchar *)) != NULL) {
type = va_arg (va, SecretSchemaAttributeType);
g_hash_table_insert (attributes, (gpointer *)attribute,
GINT_TO_POINTER (type));
}
schema = secret_schema_newv (name, flags, attributes);
g_hash_table_unref (attributes);
va_end (va);
return schema;
}
/**
* secret_schema_ref:
* @schema: the schema to reference
*
* Adds a reference to the #SecretSchema.
*
* It is not normally necessary to call this function from C code, and is
* mainly present for the sake of bindings. If the @schema was statically
* allocated, then this function will copy the schema.
*
* Returns: (transfer full): the referenced schema, which should be later
* unreferenced with secret_schema_unref()
*/
SecretSchema *
secret_schema_ref (SecretSchema *schema)
{
SecretSchema *result;
gint i;
g_return_val_if_fail (schema != NULL, NULL);
/* If it's static, then copy it */
if (g_atomic_int_get (&schema->reserved) > 0) {
g_atomic_int_inc (&schema->reserved);
result = schema;
} else {
result = g_slice_new0 (SecretSchema);
result->reserved = 1;
result->name = g_strdup (schema->name);
for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++) {
result->attributes[i].name = g_strdup (schema->attributes[i].name);
result->attributes[i].type = schema->attributes[i].type;
}
}
return result;
}
const SecretSchema *
_secret_schema_ref_if_nonstatic (const SecretSchema *schema)
{
if (schema && g_atomic_int_get (&schema->reserved) > 0)
secret_schema_ref ((SecretSchema *)schema);
return schema;
}
/**
* secret_schema_unref:
* @schema: the schema to reference
*
* Releases a reference to the #SecretSchema. If the last reference is
* released then the schema will be freed.
*
* It is not normally necessary to call this function from C code, and is
* mainly present for the sake of bindings. It is an error to call this for
* a @schema that was statically allocated.
*/
void
secret_schema_unref (SecretSchema *schema)
{
gint refs;
gint i;
g_return_if_fail (schema != NULL);
refs = g_atomic_int_add (&schema->reserved, -1);
if (refs < 0) {
g_warning ("should not unreference a static or invalid SecretSchema");
} else if (refs == 0) {
g_free ((gpointer)schema->name);
for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++)
g_free ((gpointer)schema->attributes[i].name);
g_slice_free (SecretSchema, schema);
}
}
void
_secret_schema_unref_if_nonstatic (const SecretSchema *schema)
{
if (schema && g_atomic_int_get (&schema->reserved) > 0)
secret_schema_unref ((SecretSchema *)schema);
}
G_DEFINE_BOXED_TYPE (SecretSchema, secret_schema, secret_schema_ref, secret_schema_unref);