error handling
[oweals/gnunet.git] / src / abd / plugin_gnsrecord_abd.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2013 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 abd/plugin_gnsrecord_abd.c
23  * @brief gnsrecord plugin to provide the API for ABD records
24  * @author Martin Schanzenbach
25  */
26 #include "platform.h"
27
28 #include "gnunet_util_lib.h"
29
30 #include "delegate_misc.h"
31 #include "abd_serialization.h"
32 #include "gnunet_abd_service.h"
33 #include "gnunet_gnsrecord_lib.h"
34 #include "gnunet_gnsrecord_plugin.h"
35 #include "gnunet_signatures.h"
36 /**
37  * Convert the 'value' of a record to a string.
38  *
39  * @param cls closure, unused
40  * @param type type of the record
41  * @param data value in binary encoding
42  * @param data_size number of bytes in @a data
43  * @return NULL on error, otherwise human-readable representation of the value
44  */
45 static char *
46 abd_value_to_string (void *cls,
47                      uint32_t type,
48                      const void *data,
49                      size_t data_size)
50 {
51   const char *cdata;
52
53   switch (type)
54   {
55   case GNUNET_GNSRECORD_TYPE_ATTRIBUTE:
56     {
57       struct GNUNET_ABD_DelegationRecord sets;
58       char *attr_str;
59       char *subject_pkey;
60       char *tmp_str;
61       int i;
62       if (data_size < sizeof (struct GNUNET_ABD_DelegationRecord))
63         return NULL; /* malformed */
64
65       GNUNET_memcpy (&sets, data, sizeof (sets));
66       cdata = data;
67
68       struct GNUNET_ABD_DelegationSet set[ntohl (sets.set_count)];
69       if (GNUNET_OK !=
70           GNUNET_ABD_delegation_set_deserialize (GNUNET_ntohll (
71                                                    sets.data_size),
72                                                  &cdata[sizeof (sets)],
73                                                  ntohl (sets.set_count),
74                                                  set))
75         return NULL;
76
77       for (i = 0; i < ntohl (sets.set_count); i++)
78       {
79         subject_pkey =
80           GNUNET_CRYPTO_ecdsa_public_key_to_string (&set[i].subject_key);
81
82         if (0 == set[i].subject_attribute_len)
83         {
84           if (0 == i)
85           {
86             GNUNET_asprintf (&attr_str, "%s", subject_pkey);
87           }
88           else
89           {
90             GNUNET_asprintf (&tmp_str, "%s,%s", attr_str, subject_pkey);
91             GNUNET_free (attr_str);
92             attr_str = tmp_str;
93           }
94         }
95         else
96         {
97           if (0 == i)
98           {
99             GNUNET_asprintf (&attr_str,
100                              "%s %s",
101                              subject_pkey,
102                              set[i].subject_attribute);
103           }
104           else
105           {
106             GNUNET_asprintf (&tmp_str,
107                              "%s,%s %s",
108                              attr_str,
109                              subject_pkey,
110                              set[i].subject_attribute);
111             GNUNET_free (attr_str);
112             attr_str = tmp_str;
113           }
114         }
115         GNUNET_free (subject_pkey);
116       }
117       return attr_str;
118     }
119   case GNUNET_GNSRECORD_TYPE_DELEGATE:
120     {
121       struct GNUNET_ABD_Delegate *cred;
122       char *cred_str;
123
124       cred = GNUNET_ABD_delegate_deserialize (data, data_size);
125       cred_str = GNUNET_ABD_delegate_to_string (cred);
126       GNUNET_free (cred);
127       return cred_str;
128     }
129   default:
130     return NULL;
131   }
132 }
133
134
135 /**
136  * Convert human-readable version of a 'value' of a record to the binary
137  * representation.
138  *
139  * @param cls closure, unused
140  * @param type type of the record
141  * @param s human-readable string
142  * @param data set to value in binary encoding (will be allocated)
143  * @param data_size set to number of bytes in @a data
144  * @return #GNUNET_OK on success
145  */
146 static int
147 abd_string_to_value (void *cls,
148                      uint32_t type,
149                      const char *s,
150                      void **data,
151                      size_t *data_size)
152 {
153   if (NULL == s)
154     return GNUNET_SYSERR;
155   switch (type)
156   {
157   case GNUNET_GNSRECORD_TYPE_ATTRIBUTE:
158     {
159       struct GNUNET_ABD_DelegationRecord *sets;
160       char attr_str[253 + 1];
161       char subject_pkey[52 + 1];
162       char *token;
163       char *tmp_str;
164       int matches = 0;
165       int entries;
166       size_t tmp_data_size;
167       int i;
168
169       tmp_str = GNUNET_strdup (s);
170       token = strtok (tmp_str, ",");
171       entries = 0;
172       tmp_data_size = 0;
173       *data_size = sizeof (struct GNUNET_ABD_DelegationRecord);
174       while (NULL != token)
175       {
176         // also fills the variables subject_pley and attr_str if "regex"-like match
177         matches = sscanf (token, "%s %s", subject_pkey, attr_str);
178
179         if (0 == matches)
180         {
181           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
182                       _ ("Unable to parse ATTR record string `%s'\n"),
183                       s);
184           GNUNET_free (tmp_str);
185           return GNUNET_SYSERR;
186         }
187
188         entries++;
189         token = strtok (NULL, ",");
190       }
191       GNUNET_free (tmp_str);
192
193       tmp_str = GNUNET_strdup (s);
194       token = strtok (tmp_str, ",");
195       if (NULL == token)
196       {
197         GNUNET_free (tmp_str);
198         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed string %s\n", s);
199         return GNUNET_SYSERR;
200       }
201
202       struct GNUNET_ABD_DelegationSet set[entries];
203       // sets memory to be 0, starting at *set for the size of struct * entries
204       memset (set, 0, sizeof (struct GNUNET_ABD_DelegationSet) * entries);
205       for (i = 0; i < entries; i++)
206       {
207         matches = sscanf (token, "%s %s", subject_pkey, attr_str);
208
209         // sets the public key for the set entry
210         GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_pkey,
211                                                     strlen (subject_pkey),
212                                                     &set[i].subject_key);
213
214         // If not just key, also set subject attribute (Not A.a <- B but A.a <- B.b)
215         if (2 == matches)
216         {
217           set[i].subject_attribute_len = strlen (attr_str) + 1;
218           set[i].subject_attribute = GNUNET_strdup (attr_str);
219         }
220         // If more entries, then token string can take the next entry (separated by ',') by calling strtok again
221         token = strtok (NULL, ",");
222       }
223       tmp_data_size = GNUNET_ABD_delegation_set_get_size (entries, set);
224
225       if (-1 == tmp_data_size)
226       {
227         GNUNET_free (tmp_str);
228         return GNUNET_SYSERR;
229       }
230       *data_size += tmp_data_size;
231       *data = sets = GNUNET_malloc (*data_size);
232       GNUNET_ABD_delegation_set_serialize (entries,
233                                            set,
234                                            tmp_data_size,
235                                            (char *) &sets[1]);
236       for (i = 0; i < entries; i++)
237       {
238         if (0 != set[i].subject_attribute_len)
239           GNUNET_free ((char *) set[i].subject_attribute);
240       }
241       sets->set_count = htonl (entries);
242       sets->data_size = GNUNET_htonll (tmp_data_size);
243
244       GNUNET_free (tmp_str);
245       return GNUNET_OK;
246     }
247   case GNUNET_GNSRECORD_TYPE_DELEGATE:
248     {
249       struct GNUNET_ABD_Delegate *cred;
250       cred = GNUNET_ABD_delegate_from_string (s);
251
252       *data_size = GNUNET_ABD_delegate_serialize (cred, (char **) data);
253
254       return GNUNET_OK;
255     }
256   default:
257     return GNUNET_SYSERR;
258   }
259 }
260
261
262 /**
263  * Mapping of record type numbers to human-readable
264  * record type names.
265  */
266 static struct
267 {
268   const char *name;
269   uint32_t number;
270 } name_map[] = {{"ATTR", GNUNET_GNSRECORD_TYPE_ATTRIBUTE},
271                 {"DEL", GNUNET_GNSRECORD_TYPE_DELEGATE},
272                 {NULL, UINT32_MAX}};
273
274
275 /**
276  * Convert a type name (i.e. "AAAA") to the corresponding number.
277  *
278  * @param cls closure, unused
279  * @param gns_typename name to convert
280  * @return corresponding number, UINT32_MAX on error
281  */
282 static uint32_t
283 abd_typename_to_number (void *cls, const char *gns_typename)
284 {
285   unsigned int i;
286
287   i = 0;
288   while ((name_map[i].name != NULL) &&
289          (0 != strcasecmp (gns_typename, name_map[i].name)))
290     i++;
291   return name_map[i].number;
292 }
293
294
295 /**
296  * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
297  *
298  * @param cls closure, unused
299  * @param type number of a type to convert
300  * @return corresponding typestring, NULL on error
301  */
302 static const char *
303 abd_number_to_typename (void *cls, uint32_t type)
304 {
305   unsigned int i;
306
307   i = 0;
308   while ((name_map[i].name != NULL) && (type != name_map[i].number))
309     i++;
310   return name_map[i].name;
311 }
312
313
314 /**
315  * Entry point for the plugin.
316  *
317  * @param cls NULL
318  * @return the exported block API
319  */
320 void *
321 libgnunet_plugin_gnsrecord_abd_init (void *cls)
322 {
323   struct GNUNET_GNSRECORD_PluginFunctions *api;
324
325   api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
326   api->value_to_string = &abd_value_to_string;
327   api->string_to_value = &abd_string_to_value;
328   api->typename_to_number = &abd_typename_to_number;
329   api->number_to_typename = &abd_number_to_typename;
330   return api;
331 }
332
333
334 /**
335  * Exit point from the plugin.
336  *
337  * @param cls the return value from #libgnunet_plugin_block_test_init
338  * @return NULL
339  */
340 void *
341 libgnunet_plugin_gnsrecord_abd_done (void *cls)
342 {
343   struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
344
345   GNUNET_free (api);
346   return NULL;
347 }
348
349
350 /* end of plugin_gnsrecord_abd.c */