bugfixes
[oweals/gnunet.git] / src / reclaim-attribute / reclaim_attribute.c
1 /*
2    This file is part of GNUnet
3    Copyright (C) 2010-2015 GNUnet e.V.
4
5    GNUnet is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your option) any later version.
9
10    GNUnet is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18    SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file reclaim-attribute/reclaim_attribute.c
23  * @brief helper library to manage identity attributes
24  * @author Martin Schanzenbach
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_reclaim_plugin.h"
29 #include "reclaim_attribute.h"
30
31
32 /**
33  * Handle for a plugin
34  */
35 struct Plugin
36 {
37   /**
38    * Name of the plugin
39    */
40   char *library_name;
41
42   /**
43    * Plugin API
44    */
45   struct GNUNET_RECLAIM_AttributePluginFunctions *api;
46 };
47
48
49 /**
50  * Plugins
51  */
52 static struct Plugin **attr_plugins;
53
54
55 /**
56  * Number of plugins
57  */
58 static unsigned int num_plugins;
59
60
61 /**
62  * Init canary
63  */
64 static int initialized;
65
66
67 /**
68  * Add a plugin
69  *
70  * @param cls closure
71  * @param library_name name of the API library
72  * @param lib_ret the plugin API pointer
73  */
74 static void
75 add_plugin (void *cls, const char *library_name, void *lib_ret)
76 {
77   struct GNUNET_RECLAIM_AttributePluginFunctions *api = lib_ret;
78   struct Plugin *plugin;
79
80   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
81               "Loading attribute plugin `%s'\n",
82               library_name);
83   plugin = GNUNET_new (struct Plugin);
84   plugin->api = api;
85   plugin->library_name = GNUNET_strdup (library_name);
86   GNUNET_array_append (attr_plugins, num_plugins, plugin);
87 }
88
89
90 /**
91  * Load plugins
92  */
93 static void
94 init ()
95 {
96   if (GNUNET_YES == initialized)
97     return;
98   initialized = GNUNET_YES;
99   GNUNET_PLUGIN_load_all ("libgnunet_plugin_reclaim_attribute_",
100                           NULL,
101                           &add_plugin,
102                           NULL);
103 }
104
105
106 /**
107  * Convert a type name to the corresponding number
108  *
109  * @param typename name to convert
110  * @return corresponding number, UINT32_MAX on error
111  */
112 uint32_t
113 GNUNET_RECLAIM_attribute_typename_to_number (const char *typename)
114 {
115   unsigned int i;
116   struct Plugin *plugin;
117   uint32_t ret;
118
119   init ();
120   for (i = 0; i < num_plugins; i++)
121   {
122     plugin = attr_plugins[i];
123     if (UINT32_MAX !=
124         (ret = plugin->api->typename_to_number (plugin->api->cls, typename)))
125       return ret;
126   }
127   return UINT32_MAX;
128 }
129
130
131 /**
132  * Convert a type number to the corresponding type string
133  *
134  * @param type number of a type
135  * @return corresponding typestring, NULL on error
136  */
137 const char *
138 GNUNET_RECLAIM_attribute_number_to_typename (uint32_t type)
139 {
140   unsigned int i;
141   struct Plugin *plugin;
142   const char *ret;
143
144   init ();
145   for (i = 0; i < num_plugins; i++)
146   {
147     plugin = attr_plugins[i];
148     if (NULL !=
149         (ret = plugin->api->number_to_typename (plugin->api->cls, type)))
150       return ret;
151   }
152   return NULL;
153 }
154
155
156 /**
157  * Convert human-readable version of a 'claim' of an attribute to the binary
158  * representation
159  *
160  * @param type type of the claim
161  * @param s human-readable string
162  * @param data set to value in binary encoding (will be allocated)
163  * @param data_size set to number of bytes in @a data
164  * @return #GNUNET_OK on success
165  */
166 int
167 GNUNET_RECLAIM_attribute_string_to_value (uint32_t type,
168                                           const char *s,
169                                           void **data,
170                                           size_t *data_size)
171 {
172   unsigned int i;
173   struct Plugin *plugin;
174
175   init ();
176   for (i = 0; i < num_plugins; i++)
177   {
178     plugin = attr_plugins[i];
179     if (GNUNET_OK == plugin->api->string_to_value (plugin->api->cls,
180                                                    type,
181                                                    s,
182                                                    data,
183                                                    data_size))
184       return GNUNET_OK;
185   }
186   return GNUNET_SYSERR;
187 }
188
189
190 /**
191  * Convert the 'claim' of an attribute to a string
192  *
193  * @param type the type of attribute
194  * @param data claim in binary encoding
195  * @param data_size number of bytes in @a data
196  * @return NULL on error, otherwise human-readable representation of the claim
197  */
198 char *
199 GNUNET_RECLAIM_attribute_value_to_string (uint32_t type,
200                                           const void *data,
201                                           size_t data_size)
202 {
203   unsigned int i;
204   struct Plugin *plugin;
205   char *ret;
206
207   init ();
208   for (i = 0; i < num_plugins; i++)
209   {
210     plugin = attr_plugins[i];
211     if (NULL != (ret = plugin->api->value_to_string (plugin->api->cls,
212                                                      type,
213                                                      data,
214                                                      data_size)))
215       return ret;
216   }
217   return NULL;
218 }
219
220
221 /**
222  * Create a new attribute.
223  *
224  * @param attr_name the attribute name
225  * @param attestation attestation ID of the attribute (maybe NULL)
226  * @param type the attribute type
227  * @param data the attribute value
228  * @param data_size the attribute value size
229  * @return the new attribute
230  */
231 struct GNUNET_RECLAIM_Attribute *
232 GNUNET_RECLAIM_attribute_new (const char *attr_name,
233                               const struct GNUNET_RECLAIM_Identifier *attestation,
234                               uint32_t type,
235                               const void *data,
236                               size_t data_size)
237 {
238   struct GNUNET_RECLAIM_Attribute *attr;
239   char *write_ptr;
240   char *attr_name_tmp = GNUNET_strdup (attr_name);
241
242   GNUNET_STRINGS_utf8_tolower (attr_name, attr_name_tmp);
243
244   attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Attribute)
245                         + strlen (attr_name_tmp) + 1 + data_size);
246   if (NULL != attestation)
247     attr->attestation = *attestation;
248   attr->type = type;
249   attr->data_size = data_size;
250   attr->flag = 0;
251   write_ptr = (char *) &attr[1];
252   GNUNET_memcpy (write_ptr, attr_name_tmp, strlen (attr_name_tmp) + 1);
253   attr->name = write_ptr;
254   write_ptr += strlen (attr->name) + 1;
255   GNUNET_memcpy (write_ptr, data, data_size);
256   attr->data = write_ptr;
257   GNUNET_free (attr_name_tmp);
258   return attr;
259 }
260
261
262 /**
263  * Add a new attribute to a claim list
264  *
265  * @param attr_name the name of the new attribute claim
266  * @param type the type of the claim
267  * @param data claim payload
268  * @param data_size claim payload size
269  */
270 void
271 GNUNET_RECLAIM_attribute_list_add (
272   struct GNUNET_RECLAIM_AttributeList *al,
273   const char *attr_name,
274   const struct GNUNET_RECLAIM_Identifier *attestation,
275   uint32_t type,
276   const void *data,
277   size_t data_size)
278 {
279   struct GNUNET_RECLAIM_AttributeListEntry *ale;
280
281   ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
282   ale->attribute =
283     GNUNET_RECLAIM_attribute_new (attr_name, attestation,
284                                   type, data, data_size);
285   GNUNET_CONTAINER_DLL_insert (al->list_head,
286                                al->list_tail,
287                                ale);
288 }
289
290
291 /**
292  * Get required size for serialization buffer
293  *
294  * @param attrs the attribute list to serialize
295  * @return the required buffer size
296  */
297 size_t
298 GNUNET_RECLAIM_attribute_list_serialize_get_size (
299   const struct GNUNET_RECLAIM_AttributeList *al)
300 {
301   struct GNUNET_RECLAIM_AttributeListEntry *ale;
302   size_t len = 0;
303
304   for (ale = al->list_head; NULL != ale; ale = ale->next)
305   {
306     GNUNET_assert (NULL != ale->attribute);
307     len += GNUNET_RECLAIM_attribute_serialize_get_size (ale->attribute);
308     len += sizeof(struct GNUNET_RECLAIM_AttributeListEntry);
309   }
310   return len;
311 }
312
313
314 /**
315  * Serialize an attribute list
316  *
317  * @param attrs the attribute list to serialize
318  * @param result the serialized attribute
319  * @return length of serialized data
320  */
321 size_t
322 GNUNET_RECLAIM_attribute_list_serialize (
323   const struct GNUNET_RECLAIM_AttributeList *al,
324   char *result)
325 {
326   struct GNUNET_RECLAIM_AttributeListEntry *ale;
327   size_t len;
328   size_t total_len;
329   char *write_ptr;
330   write_ptr = result;
331   total_len = 0;
332   for (ale = al->list_head; NULL != ale; ale = ale->next)
333   {
334     GNUNET_assert (NULL != ale->attribute);
335     len = GNUNET_RECLAIM_attribute_serialize (ale->attribute, write_ptr);
336     total_len += len;
337     write_ptr += len;
338   }
339   return total_len;
340 }
341
342
343 /**
344  * Deserialize an attribute list
345  *
346  * @param data the serialized attribute list
347  * @param data_size the length of the serialized data
348  * @return a GNUNET_IDENTITY_PROVIDER_AttributeList, must be free'd by caller
349  */
350 struct GNUNET_RECLAIM_AttributeList *
351 GNUNET_RECLAIM_attribute_list_deserialize (const char *data, size_t data_size)
352 {
353   struct GNUNET_RECLAIM_AttributeList *al;
354   struct GNUNET_RECLAIM_AttributeListEntry *ale;
355   size_t attr_len;
356   const char *read_ptr;
357
358   al = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
359   if (data_size < sizeof(struct Attribute) + sizeof(struct
360                                                     GNUNET_RECLAIM_AttributeListEntry))
361     return al;
362   read_ptr = data;
363   while (((data + data_size) - read_ptr) >= sizeof(struct Attribute))
364   {
365     ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
366     ale->attribute =
367       GNUNET_RECLAIM_attribute_deserialize (read_ptr,
368                                             data_size - (read_ptr - data));
369     GNUNET_CONTAINER_DLL_insert (al->list_head, al->list_tail, ale);
370     attr_len = GNUNET_RECLAIM_attribute_serialize_get_size (ale->attribute);
371     read_ptr += attr_len;
372   }
373   return al;
374 }
375
376
377 /**
378  * Make a (deep) copy of a claim list
379  * @param attrs claim list to copy
380  * @return copied claim list
381  */
382 struct GNUNET_RECLAIM_AttributeList *
383 GNUNET_RECLAIM_attribute_list_dup (
384   const struct GNUNET_RECLAIM_AttributeList *al)
385 {
386   struct GNUNET_RECLAIM_AttributeListEntry *ale;
387   struct GNUNET_RECLAIM_AttributeListEntry *result_ale;
388   struct GNUNET_RECLAIM_AttributeList *result;
389
390   result = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
391   for (ale = al->list_head; NULL != ale; ale = ale->next)
392   {
393     result_ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
394     GNUNET_assert (NULL != ale->attribute);
395     {
396       result_ale->attribute =
397         GNUNET_RECLAIM_attribute_new (ale->attribute->name,
398                                       &ale->attribute->attestation,
399                                       ale->attribute->type,
400                                       ale->attribute->data,
401                                       ale->attribute->data_size);
402
403       result_ale->attribute->id = ale->attribute->id;
404       result_ale->attribute->flag = ale->attribute->flag;
405     }
406     GNUNET_CONTAINER_DLL_insert (result->list_head,
407                                  result->list_tail,
408                                  result_ale);
409   }
410   return result;
411 }
412
413
414 /**
415  * Destroy claim list
416  *
417  * @param attrs list to destroy
418  */
419 void
420 GNUNET_RECLAIM_attribute_list_destroy (
421   struct GNUNET_RECLAIM_AttributeList *al)
422 {
423   struct GNUNET_RECLAIM_AttributeListEntry *ale;
424   struct GNUNET_RECLAIM_AttributeListEntry *tmp_ale;
425
426   for (ale = al->list_head; NULL != ale;)
427   {
428     if (NULL != ale->attribute)
429       GNUNET_free (ale->attribute);
430     tmp_ale = ale;
431     ale = ale->next;
432     GNUNET_free (tmp_ale);
433   }
434   GNUNET_free (al);
435 }
436
437
438 /**
439  * Get required size for serialization buffer
440  *
441  * @param attr the attribute to serialize
442  * @return the required buffer size
443  */
444 size_t
445 GNUNET_RECLAIM_attribute_serialize_get_size (
446   const struct GNUNET_RECLAIM_Attribute *attr)
447 {
448   return sizeof(struct Attribute) + strlen (attr->name) + attr->data_size;
449 }
450
451
452 /**
453  * Serialize an attribute
454  *
455  * @param attr the attribute to serialize
456  * @param result the serialized attribute
457  * @return length of serialized data
458  */
459 size_t
460 GNUNET_RECLAIM_attribute_serialize (
461   const struct GNUNET_RECLAIM_Attribute *attr,
462   char *result)
463 {
464   size_t data_len_ser;
465   size_t name_len;
466   struct Attribute *attr_ser;
467   char *write_ptr;
468
469   attr_ser = (struct Attribute *) result;
470   attr_ser->attribute_type = htons (attr->type);
471   attr_ser->attribute_flag = htonl (attr->flag);
472   attr_ser->attribute_id = attr->id;
473   name_len = strlen (attr->name);
474   attr_ser->name_len = htons (name_len);
475   write_ptr = (char *) &attr_ser[1];
476   GNUNET_memcpy (write_ptr, attr->name, name_len);
477   write_ptr += name_len;
478   // TODO plugin-ize
479   // data_len_ser = plugin->serialize_attribute_value (attr,
480   //                                                  &attr_ser[1]);
481   data_len_ser = attr->data_size;
482   GNUNET_memcpy (write_ptr, attr->data, attr->data_size);
483   attr_ser->data_size = htons (data_len_ser);
484
485   return sizeof(struct Attribute) + strlen (attr->name) + attr->data_size;
486 }
487
488
489 /**
490  * Deserialize an attribute
491  *
492  * @param data the serialized attribute
493  * @param data_size the length of the serialized data
494  *
495  * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller
496  */
497 struct GNUNET_RECLAIM_Attribute *
498 GNUNET_RECLAIM_attribute_deserialize (const char *data, size_t data_size)
499 {
500   struct GNUNET_RECLAIM_Attribute *attr;
501   struct Attribute *attr_ser;
502   size_t data_len;
503   size_t name_len;
504   char *write_ptr;
505
506   if (data_size < sizeof(struct Attribute))
507     return NULL;
508
509   attr_ser = (struct Attribute *) data;
510   data_len = ntohs (attr_ser->data_size);
511   name_len = ntohs (attr_ser->name_len);
512   if (data_size < sizeof(struct Attribute) + data_len + name_len)
513   {
514     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
515                 "Buffer too small to deserialize\n");
516     return NULL;
517   }
518   attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Attribute)
519                         + data_len + name_len + 1);
520   attr->type = ntohs (attr_ser->attribute_type);
521   attr->flag = ntohl (attr_ser->attribute_flag);
522   attr->id = attr_ser->attribute_id;
523   attr->data_size = data_len;
524
525   write_ptr = (char *) &attr[1];
526   GNUNET_memcpy (write_ptr, &attr_ser[1], name_len);
527   write_ptr[name_len] = '\0';
528   attr->name = write_ptr;
529
530   write_ptr += name_len + 1;
531   GNUNET_memcpy (write_ptr, (char *) &attr_ser[1] + name_len, attr->data_size);
532   attr->data = write_ptr;
533   return attr;
534 }
535
536
537 /* end of reclaim_attribute.c */