error handling
[oweals/gnunet.git] / src / reclaim / 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     if (NULL == ale->attribute)
370     {
371       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
372                   "Failed to deserialize malformed attribute.\n");
373       GNUNET_free (ale);
374       return al;
375     }
376     GNUNET_CONTAINER_DLL_insert (al->list_head, al->list_tail, ale);
377     attr_len = GNUNET_RECLAIM_attribute_serialize_get_size (ale->attribute);
378     read_ptr += attr_len;
379   }
380   return al;
381 }
382
383
384 /**
385  * Make a (deep) copy of a claim list
386  * @param attrs claim list to copy
387  * @return copied claim list
388  */
389 struct GNUNET_RECLAIM_AttributeList *
390 GNUNET_RECLAIM_attribute_list_dup (
391   const struct GNUNET_RECLAIM_AttributeList *al)
392 {
393   struct GNUNET_RECLAIM_AttributeListEntry *ale;
394   struct GNUNET_RECLAIM_AttributeListEntry *result_ale;
395   struct GNUNET_RECLAIM_AttributeList *result;
396
397   result = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
398   for (ale = al->list_head; NULL != ale; ale = ale->next)
399   {
400     result_ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
401     GNUNET_assert (NULL != ale->attribute);
402     {
403       result_ale->attribute =
404         GNUNET_RECLAIM_attribute_new (ale->attribute->name,
405                                       &ale->attribute->attestation,
406                                       ale->attribute->type,
407                                       ale->attribute->data,
408                                       ale->attribute->data_size);
409
410       result_ale->attribute->id = ale->attribute->id;
411       result_ale->attribute->flag = ale->attribute->flag;
412     }
413     GNUNET_CONTAINER_DLL_insert (result->list_head,
414                                  result->list_tail,
415                                  result_ale);
416   }
417   return result;
418 }
419
420
421 /**
422  * Destroy claim list
423  *
424  * @param attrs list to destroy
425  */
426 void
427 GNUNET_RECLAIM_attribute_list_destroy (
428   struct GNUNET_RECLAIM_AttributeList *al)
429 {
430   struct GNUNET_RECLAIM_AttributeListEntry *ale;
431   struct GNUNET_RECLAIM_AttributeListEntry *tmp_ale;
432
433   for (ale = al->list_head; NULL != ale;)
434   {
435     if (NULL != ale->attribute)
436       GNUNET_free (ale->attribute);
437     tmp_ale = ale;
438     ale = ale->next;
439     GNUNET_free (tmp_ale);
440   }
441   GNUNET_free (al);
442 }
443
444
445 /**
446  * Get required size for serialization buffer
447  *
448  * @param attr the attribute to serialize
449  * @return the required buffer size
450  */
451 size_t
452 GNUNET_RECLAIM_attribute_serialize_get_size (
453   const struct GNUNET_RECLAIM_Attribute *attr)
454 {
455   return sizeof(struct Attribute) + strlen (attr->name) + attr->data_size;
456 }
457
458
459 /**
460  * Serialize an attribute
461  *
462  * @param attr the attribute to serialize
463  * @param result the serialized attribute
464  * @return length of serialized data
465  */
466 size_t
467 GNUNET_RECLAIM_attribute_serialize (
468   const struct GNUNET_RECLAIM_Attribute *attr,
469   char *result)
470 {
471   size_t data_len_ser;
472   size_t name_len;
473   struct Attribute *attr_ser;
474   char *write_ptr;
475
476   attr_ser = (struct Attribute *) result;
477   attr_ser->attribute_type = htons (attr->type);
478   attr_ser->attribute_flag = htonl (attr->flag);
479   attr_ser->attribute_id = attr->id;
480   attr_ser->attestation_id = attr->attestation;
481   name_len = strlen (attr->name);
482   attr_ser->name_len = htons (name_len);
483   write_ptr = (char *) &attr_ser[1];
484   GNUNET_memcpy (write_ptr, attr->name, name_len);
485   write_ptr += name_len;
486   // TODO plugin-ize
487   // data_len_ser = plugin->serialize_attribute_value (attr,
488   //                                                  &attr_ser[1]);
489   data_len_ser = attr->data_size;
490   GNUNET_memcpy (write_ptr, attr->data, attr->data_size);
491   attr_ser->data_size = htons (data_len_ser);
492
493   return sizeof(struct Attribute) + strlen (attr->name) + attr->data_size;
494 }
495
496
497 /**
498  * Deserialize an attribute
499  *
500  * @param data the serialized attribute
501  * @param data_size the length of the serialized data
502  *
503  * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller
504  */
505 struct GNUNET_RECLAIM_Attribute *
506 GNUNET_RECLAIM_attribute_deserialize (const char *data, size_t data_size)
507 {
508   struct GNUNET_RECLAIM_Attribute *attr;
509   struct Attribute *attr_ser;
510   size_t data_len;
511   size_t name_len;
512   char *write_ptr;
513
514   if (data_size < sizeof(struct Attribute))
515     return NULL;
516
517   attr_ser = (struct Attribute *) data;
518   data_len = ntohs (attr_ser->data_size);
519   name_len = ntohs (attr_ser->name_len);
520   if (data_size < sizeof(struct Attribute) + data_len + name_len)
521   {
522     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
523                 "Buffer too small to deserialize\n");
524     return NULL;
525   }
526   attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Attribute)
527                         + data_len + name_len + 1);
528   attr->type = ntohs (attr_ser->attribute_type);
529   attr->flag = ntohl (attr_ser->attribute_flag);
530   attr->id = attr_ser->attribute_id;
531   attr->attestation = attr_ser->attestation_id;
532   attr->data_size = data_len;
533
534   write_ptr = (char *) &attr[1];
535   GNUNET_memcpy (write_ptr, &attr_ser[1], name_len);
536   write_ptr[name_len] = '\0';
537   attr->name = write_ptr;
538
539   write_ptr += name_len + 1;
540   GNUNET_memcpy (write_ptr, (char *) &attr_ser[1] + name_len, attr->data_size);
541   attr->data = write_ptr;
542   return attr;
543 }
544
545
546 /* end of reclaim_attribute.c */