/* This file is part of GNUnet Copyright (C) 2010-2015 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . SPDX-License-Identifier: AGPL3.0-or-later */ /** * @file reclaim-attribute/reclaim_attribute.c * @brief helper library to manage identity attributes * @author Martin Schanzenbach */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_reclaim_plugin.h" #include "reclaim_attribute.h" /** * Handle for a plugin */ struct Plugin { /** * Name of the plugin */ char *library_name; /** * Plugin API */ struct GNUNET_RECLAIM_AttributePluginFunctions *api; }; /** * Plugins */ static struct Plugin **attr_plugins; /** * Number of plugins */ static unsigned int num_plugins; /** * Init canary */ static int initialized; /** * Add a plugin * * @param cls closure * @param library_name name of the API library * @param lib_ret the plugin API pointer */ static void add_plugin (void *cls, const char *library_name, void *lib_ret) { struct GNUNET_RECLAIM_AttributePluginFunctions *api = lib_ret; struct Plugin *plugin; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading attribute plugin `%s'\n", library_name); plugin = GNUNET_new (struct Plugin); plugin->api = api; plugin->library_name = GNUNET_strdup (library_name); GNUNET_array_append (attr_plugins, num_plugins, plugin); } /** * Load plugins */ static void init () { if (GNUNET_YES == initialized) return; initialized = GNUNET_YES; GNUNET_PLUGIN_load_all ("libgnunet_plugin_reclaim_attribute_", NULL, &add_plugin, NULL); } /** * Convert a type name to the corresponding number * * @param typename name to convert * @return corresponding number, UINT32_MAX on error */ uint32_t GNUNET_RECLAIM_attribute_typename_to_number (const char *typename) { unsigned int i; struct Plugin *plugin; uint32_t ret; init (); for (i = 0; i < num_plugins; i++) { plugin = attr_plugins[i]; if (UINT32_MAX != (ret = plugin->api->typename_to_number (plugin->api->cls, typename))) return ret; } return UINT32_MAX; } /** * Convert a type number to the corresponding type string * * @param type number of a type * @return corresponding typestring, NULL on error */ const char * GNUNET_RECLAIM_attribute_number_to_typename (uint32_t type) { unsigned int i; struct Plugin *plugin; const char *ret; init (); for (i = 0; i < num_plugins; i++) { plugin = attr_plugins[i]; if (NULL != (ret = plugin->api->number_to_typename (plugin->api->cls, type))) return ret; } return NULL; } /** * Convert human-readable version of a 'claim' of an attribute to the binary * representation * * @param type type of the claim * @param s human-readable string * @param data set to value in binary encoding (will be allocated) * @param data_size set to number of bytes in @a data * @return #GNUNET_OK on success */ int GNUNET_RECLAIM_attribute_string_to_value (uint32_t type, const char *s, void **data, size_t *data_size) { unsigned int i; struct Plugin *plugin; init (); for (i = 0; i < num_plugins; i++) { plugin = attr_plugins[i]; if (GNUNET_OK == plugin->api->string_to_value (plugin->api->cls, type, s, data, data_size)) return GNUNET_OK; } return GNUNET_SYSERR; } /** * Convert the 'claim' of an attribute to a string * * @param type the type of attribute * @param data claim in binary encoding * @param data_size number of bytes in @a data * @return NULL on error, otherwise human-readable representation of the claim */ char * GNUNET_RECLAIM_attribute_value_to_string (uint32_t type, const void *data, size_t data_size) { unsigned int i; struct Plugin *plugin; char *ret; init (); for (i = 0; i < num_plugins; i++) { plugin = attr_plugins[i]; if (NULL != (ret = plugin->api->value_to_string (plugin->api->cls, type, data, data_size))) return ret; } return NULL; } /** * Create a new attribute. * * @param attr_name the attribute name * @param attestation attestation ID of the attribute (maybe NULL) * @param type the attribute type * @param data the attribute value * @param data_size the attribute value size * @return the new attribute */ struct GNUNET_RECLAIM_Attribute * GNUNET_RECLAIM_attribute_new (const char *attr_name, const struct GNUNET_RECLAIM_Identifier *attestation, uint32_t type, const void *data, size_t data_size) { struct GNUNET_RECLAIM_Attribute *attr; char *write_ptr; char *attr_name_tmp = GNUNET_strdup (attr_name); GNUNET_STRINGS_utf8_tolower (attr_name, attr_name_tmp); attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Attribute) + strlen (attr_name_tmp) + 1 + data_size); if (NULL != attestation) attr->attestation = *attestation; attr->type = type; attr->data_size = data_size; attr->flag = 0; write_ptr = (char *) &attr[1]; GNUNET_memcpy (write_ptr, attr_name_tmp, strlen (attr_name_tmp) + 1); attr->name = write_ptr; write_ptr += strlen (attr->name) + 1; GNUNET_memcpy (write_ptr, data, data_size); attr->data = write_ptr; GNUNET_free (attr_name_tmp); return attr; } /** * Add a new attribute to a claim list * * @param attr_name the name of the new attribute claim * @param type the type of the claim * @param data claim payload * @param data_size claim payload size */ void GNUNET_RECLAIM_attribute_list_add ( struct GNUNET_RECLAIM_AttributeList *al, const char *attr_name, const struct GNUNET_RECLAIM_Identifier *attestation, uint32_t type, const void *data, size_t data_size) { struct GNUNET_RECLAIM_AttributeListEntry *ale; ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry); ale->attribute = GNUNET_RECLAIM_attribute_new (attr_name, attestation, type, data, data_size); GNUNET_CONTAINER_DLL_insert (al->list_head, al->list_tail, ale); } /** * Get required size for serialization buffer * * @param attrs the attribute list to serialize * @return the required buffer size */ size_t GNUNET_RECLAIM_attribute_list_serialize_get_size ( const struct GNUNET_RECLAIM_AttributeList *al) { struct GNUNET_RECLAIM_AttributeListEntry *ale; size_t len = 0; for (ale = al->list_head; NULL != ale; ale = ale->next) { GNUNET_assert (NULL != ale->attribute); len += GNUNET_RECLAIM_attribute_serialize_get_size (ale->attribute); } return len; } /** * Serialize an attribute list * * @param attrs the attribute list to serialize * @param result the serialized attribute * @return length of serialized data */ size_t GNUNET_RECLAIM_attribute_list_serialize ( const struct GNUNET_RECLAIM_AttributeList *al, char *result) { struct GNUNET_RECLAIM_AttributeListEntry *ale; size_t len; size_t total_len; char *write_ptr; write_ptr = result; total_len = 0; for (ale = al->list_head; NULL != ale; ale = ale->next) { GNUNET_assert (NULL != ale->attribute); len = GNUNET_RECLAIM_attribute_serialize (ale->attribute, write_ptr); total_len += len; write_ptr += len; } return total_len; } /** * Deserialize an attribute list * * @param data the serialized attribute list * @param data_size the length of the serialized data * @return a GNUNET_IDENTITY_PROVIDER_AttributeList, must be free'd by caller */ struct GNUNET_RECLAIM_AttributeList * GNUNET_RECLAIM_attribute_list_deserialize (const char *data, size_t data_size) { struct GNUNET_RECLAIM_AttributeList *al; struct GNUNET_RECLAIM_AttributeListEntry *ale; size_t attr_len; const char *read_ptr; size_t left = data_size; al = GNUNET_new (struct GNUNET_RECLAIM_AttributeList); if (data_size < sizeof(struct Attribute)) return al; read_ptr = data; while (left >= sizeof(struct Attribute)) { ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry); attr_len = GNUNET_RECLAIM_attribute_deserialize (read_ptr, left, &ale->attribute); if (-1 == attr_len) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to deserialize malformed attribute.\n"); GNUNET_free (ale); return al; } left -= attr_len; GNUNET_CONTAINER_DLL_insert (al->list_head, al->list_tail, ale); read_ptr += attr_len; } return al; } /** * Make a (deep) copy of a claim list * @param attrs claim list to copy * @return copied claim list */ struct GNUNET_RECLAIM_AttributeList * GNUNET_RECLAIM_attribute_list_dup ( const struct GNUNET_RECLAIM_AttributeList *al) { struct GNUNET_RECLAIM_AttributeListEntry *ale; struct GNUNET_RECLAIM_AttributeListEntry *result_ale; struct GNUNET_RECLAIM_AttributeList *result; result = GNUNET_new (struct GNUNET_RECLAIM_AttributeList); for (ale = al->list_head; NULL != ale; ale = ale->next) { result_ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry); GNUNET_assert (NULL != ale->attribute); { result_ale->attribute = GNUNET_RECLAIM_attribute_new (ale->attribute->name, &ale->attribute->attestation, ale->attribute->type, ale->attribute->data, ale->attribute->data_size); result_ale->attribute->id = ale->attribute->id; result_ale->attribute->flag = ale->attribute->flag; } GNUNET_CONTAINER_DLL_insert (result->list_head, result->list_tail, result_ale); } return result; } /** * Destroy claim list * * @param attrs list to destroy */ void GNUNET_RECLAIM_attribute_list_destroy ( struct GNUNET_RECLAIM_AttributeList *al) { struct GNUNET_RECLAIM_AttributeListEntry *ale; struct GNUNET_RECLAIM_AttributeListEntry *tmp_ale; for (ale = al->list_head; NULL != ale;) { if (NULL != ale->attribute) GNUNET_free (ale->attribute); tmp_ale = ale; ale = ale->next; GNUNET_free (tmp_ale); } GNUNET_free (al); } /** * Get required size for serialization buffer * * @param attr the attribute to serialize * @return the required buffer size */ size_t GNUNET_RECLAIM_attribute_serialize_get_size ( const struct GNUNET_RECLAIM_Attribute *attr) { return sizeof(struct Attribute) + strlen (attr->name) + attr->data_size; } /** * Serialize an attribute * * @param attr the attribute to serialize * @param result the serialized attribute * @return length of serialized data */ size_t GNUNET_RECLAIM_attribute_serialize ( const struct GNUNET_RECLAIM_Attribute *attr, char *result) { size_t data_len_ser; size_t name_len; struct Attribute *attr_ser; char *write_ptr; attr_ser = (struct Attribute *) result; attr_ser->attribute_type = htons (attr->type); attr_ser->attribute_flag = htonl (attr->flag); attr_ser->attribute_id = attr->id; attr_ser->attestation_id = attr->attestation; name_len = strlen (attr->name); attr_ser->name_len = htons (name_len); write_ptr = (char *) &attr_ser[1]; GNUNET_memcpy (write_ptr, attr->name, name_len); write_ptr += name_len; // TODO plugin-ize // data_len_ser = plugin->serialize_attribute_value (attr, // &attr_ser[1]); data_len_ser = attr->data_size; GNUNET_memcpy (write_ptr, attr->data, attr->data_size); attr_ser->data_size = htons (data_len_ser); return sizeof(struct Attribute) + strlen (attr->name) + attr->data_size; } /** * Deserialize an attribute * * @param data the serialized attribute * @param data_size the length of the serialized data * * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller */ ssize_t GNUNET_RECLAIM_attribute_deserialize (const char *data, size_t data_size, struct GNUNET_RECLAIM_Attribute **attr) { struct Attribute *attr_ser; struct GNUNET_RECLAIM_Attribute *attribute; size_t data_len; size_t name_len; char *write_ptr; if (data_size < sizeof(struct Attribute)) return -1; attr_ser = (struct Attribute *) data; data_len = ntohs (attr_ser->data_size); name_len = ntohs (attr_ser->name_len); if (data_size < sizeof(struct Attribute) + data_len + name_len) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Buffer too small to deserialize\n"); return -1; } attribute = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Attribute) + data_len + name_len + 1); attribute->type = ntohs (attr_ser->attribute_type); attribute->flag = ntohl (attr_ser->attribute_flag); attribute->id = attr_ser->attribute_id; attribute->attestation = attr_ser->attestation_id; attribute->data_size = data_len; write_ptr = (char *) &attribute[1]; GNUNET_memcpy (write_ptr, &attr_ser[1], name_len); write_ptr[name_len] = '\0'; attribute->name = write_ptr; write_ptr += name_len + 1; GNUNET_memcpy (write_ptr, (char *) &attr_ser[1] + name_len, attribute->data_size); *attr = attribute; attribute->data = write_ptr; return sizeof(struct Attribute) + data_len + name_len; } /* end of reclaim_attribute.c */