Merge branch 'master' of gnunet.org:gnunet
[oweals/gnunet.git] / src / credential / plugin_gnsrecord_credential.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
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file credential/plugin_gnsrecord_credential.c
23  * @brief gnsrecord plugin to provide the API for CREDENTIAL records
24  * @author Martin Schanzenbach
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_gnsrecord_lib.h"
30 #include "gnunet_credential_service.h"
31 #include "gnunet_gnsrecord_plugin.h"
32 #include "gnunet_signatures.h"
33 #include "credential_serialization.h"
34 #include "credential_misc.h"
35
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 credential_value_to_string (void *cls,
47                               uint32_t type,
48                               const void *data,
49                               size_t data_size)
50 {
51
52   const char *cdata;
53
54   switch (type)
55   {
56    case GNUNET_GNSRECORD_TYPE_ATTRIBUTE:
57    {
58     struct GNUNET_CREDENTIAL_DelegationRecord sets;
59     char *attr_str;
60     char *subject_pkey;
61     char *tmp_str;
62     int i;
63     if (data_size < sizeof (struct GNUNET_CREDENTIAL_DelegationRecord))
64       return NULL; /* malformed */
65     GNUNET_memcpy (&sets,
66                    data,
67                    sizeof (sets));
68     cdata = data;
69     struct GNUNET_CREDENTIAL_DelegationSet set[ntohl(sets.set_count)];
70     if (GNUNET_OK != GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll (sets.data_size),
71                                                                    &cdata[sizeof (sets)],
72                                                                    ntohl (sets.set_count),
73                                                                    set))
74       return NULL;
75
76     for (i=0;i<ntohl(sets.set_count);i++)
77     {
78       subject_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&set[i].subject_key);
79       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
80                   "%d len attr\n", set[i].subject_attribute_len);
81       if (0 == set[i].subject_attribute_len)
82       {
83         if (0 == i)
84         {
85           GNUNET_asprintf (&attr_str,
86                            "%s",
87                            subject_pkey);
88         } else {
89           GNUNET_asprintf (&tmp_str,
90                            "%s,%s",
91                            attr_str,
92                            subject_pkey);
93           GNUNET_free (attr_str);
94           attr_str = tmp_str;
95         }
96       } else {
97         if (0 == i)
98         {
99           GNUNET_asprintf (&attr_str,
100                            "%s %s",
101                            subject_pkey,
102                            set[i].subject_attribute);
103         } else {
104           GNUNET_asprintf (&tmp_str,
105                            "%s,%s %s",
106                            attr_str,
107                            subject_pkey,
108                            set[i].subject_attribute);
109           GNUNET_free (attr_str);
110           attr_str = tmp_str;
111         }
112       }
113       GNUNET_free (subject_pkey);
114     }
115     return attr_str;
116    }
117    case GNUNET_GNSRECORD_TYPE_CREDENTIAL:
118    {
119      struct GNUNET_CREDENTIAL_Credential *cred;
120      char *cred_str;
121
122      cred = GNUNET_CREDENTIAL_credential_deserialize (data,
123                                                       data_size);
124      cred_str = GNUNET_CREDENTIAL_credential_to_string (cred);
125      GNUNET_free (cred);
126      return cred_str;
127    }
128    case GNUNET_GNSRECORD_TYPE_POLICY:
129    {
130      return GNUNET_strndup (data,data_size);
131    }
132    default:
133    return NULL;
134   }
135 }
136
137
138 /**
139  * Convert human-readable version of a 'value' of a record to the binary
140  * representation.
141  *
142  * @param cls closure, unused
143  * @param type type of the record
144  * @param s human-readable string
145  * @param data set to value in binary encoding (will be allocated)
146  * @param data_size set to number of bytes in @a data
147  * @return #GNUNET_OK on success
148  */
149 static int
150 credential_string_to_value (void *cls,
151                             uint32_t type,
152                             const char *s,
153                             void **data,
154                             size_t *data_size)
155 {
156   if (NULL == s)
157     return GNUNET_SYSERR;
158   switch (type)
159   {
160     case GNUNET_GNSRECORD_TYPE_ATTRIBUTE:
161       {
162         struct GNUNET_CREDENTIAL_DelegationRecord *sets;
163         char attr_str[253 + 1];
164         char subject_pkey[52 + 1];
165         char *token;
166         char *tmp_str;
167         int matches = 0;
168         int entries;
169         size_t tmp_data_size;
170         int i;
171
172         tmp_str = GNUNET_strdup (s);
173         token = strtok (tmp_str, ",");
174         entries = 0;
175         tmp_data_size = 0;
176         *data_size = sizeof (struct GNUNET_CREDENTIAL_DelegationRecord);
177         while (NULL != token)
178         {
179           matches = SSCANF (token,
180                             "%s %s",
181                             subject_pkey,
182                             attr_str);
183           if (0 == matches)
184           {
185             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
186                         _("Unable to parse ATTR record string `%s'\n"),
187                         s);
188             GNUNET_free (tmp_str);
189             return GNUNET_SYSERR;
190           }
191           if (1 == matches) {
192             tmp_data_size += sizeof (struct GNUNET_CREDENTIAL_DelegationRecordSet);
193           } else if (2 == matches) {
194             tmp_data_size += sizeof (struct GNUNET_CREDENTIAL_DelegationRecordSet) + strlen (attr_str) + 1;
195           }
196           entries++;
197           token = strtok (NULL, ",");
198         }
199         GNUNET_free (tmp_str);
200         tmp_str = GNUNET_strdup (s);
201         token = strtok (tmp_str, ",");
202         if (NULL == token)
203         {
204           GNUNET_free (tmp_str);
205           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
206                       "Malformed string %s\n", s);
207           return GNUNET_SYSERR;
208         }
209         struct GNUNET_CREDENTIAL_DelegationSet set[entries];
210         for (i=0;i<entries;i++)
211         {
212           matches = SSCANF (token,
213                             "%s %s",
214                             subject_pkey,
215                             attr_str);
216           GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_pkey,
217                                                       strlen (subject_pkey),
218                                                       &set[i].subject_key);
219           if (2 == matches) {
220             set[i].subject_attribute_len = strlen (attr_str) + 1;
221             set[i].subject_attribute = GNUNET_strdup (attr_str);
222           }
223           token = strtok (NULL , ",");
224         }
225         tmp_data_size = GNUNET_CREDENTIAL_delegation_set_get_size (entries,
226                                                                    set);
227
228         if (-1 == tmp_data_size)
229         {
230           GNUNET_free (tmp_str);
231           return GNUNET_SYSERR;
232         }
233         *data_size += tmp_data_size;
234         *data = sets = GNUNET_malloc (*data_size);
235         GNUNET_CREDENTIAL_delegation_set_serialize (entries,
236                                                     set,
237                                                     tmp_data_size,
238                                                     (char*)&sets[1]);
239         for (i=0;i<entries;i++)
240         {
241           if (0 != set[i].subject_attribute_len)
242             GNUNET_free ((char*)set[i].subject_attribute);
243         }
244         sets->set_count = htonl (entries);
245         sets->data_size = GNUNET_htonll (tmp_data_size);
246
247         GNUNET_free (tmp_str);
248         return GNUNET_OK;
249       }
250     case GNUNET_GNSRECORD_TYPE_CREDENTIAL:
251       {
252         struct GNUNET_CREDENTIAL_Credential *cred;
253         cred = GNUNET_CREDENTIAL_credential_from_string (s);
254
255         *data_size = GNUNET_CREDENTIAL_credential_serialize (cred,
256                                                              (char**)data);
257         return GNUNET_OK;
258       }
259     case GNUNET_GNSRECORD_TYPE_POLICY:
260       {
261         *data_size = strlen (s);
262         *data = GNUNET_strdup (s);
263         return GNUNET_OK;
264       }
265     default:
266       return GNUNET_SYSERR;
267   }
268 }
269
270
271 /**
272  * Mapping of record type numbers to human-readable
273  * record type names.
274  */
275 static struct {
276   const char *name;
277   uint32_t number;
278 } name_map[] = {
279   { "CRED", GNUNET_GNSRECORD_TYPE_CREDENTIAL },
280   { "ATTR", GNUNET_GNSRECORD_TYPE_ATTRIBUTE },
281   { "POLICY", GNUNET_GNSRECORD_TYPE_POLICY },
282   { NULL, UINT32_MAX }
283 };
284
285
286 /**
287  * Convert a type name (i.e. "AAAA") to the corresponding number.
288  *
289  * @param cls closure, unused
290  * @param gns_typename name to convert
291  * @return corresponding number, UINT32_MAX on error
292  */
293 static uint32_t
294 credential_typename_to_number (void *cls,
295                                const char *gns_typename)
296 {
297   unsigned int i;
298
299   i=0;
300   while ( (name_map[i].name != NULL) &&
301           (0 != strcasecmp (gns_typename, name_map[i].name)) )
302     i++;
303   return name_map[i].number;
304 }
305
306
307 /**
308  * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
309  *
310  * @param cls closure, unused
311  * @param type number of a type to convert
312  * @return corresponding typestring, NULL on error
313  */
314 static const char *
315 credential_number_to_typename (void *cls,
316                                uint32_t type)
317 {
318   unsigned int i;
319
320   i=0;
321   while ( (name_map[i].name != NULL) &&
322           (type != name_map[i].number) )
323     i++;
324   return name_map[i].name;
325 }
326
327
328 /**
329  * Entry point for the plugin.
330  *
331  * @param cls NULL
332  * @return the exported block API
333  */
334 void *
335 libgnunet_plugin_gnsrecord_credential_init (void *cls)
336 {
337   struct GNUNET_GNSRECORD_PluginFunctions *api;
338
339   api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
340   api->value_to_string = &credential_value_to_string;
341   api->string_to_value = &credential_string_to_value;
342   api->typename_to_number = &credential_typename_to_number;
343   api->number_to_typename = &credential_number_to_typename;
344   return api;
345 }
346
347
348 /**
349  * Exit point from the plugin.
350  *
351  * @param cls the return value from #libgnunet_plugin_block_test_init
352  * @return NULL
353  */
354 void *
355 libgnunet_plugin_gnsrecord_credential_done (void *cls)
356 {
357   struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
358
359   GNUNET_free (api);
360   return NULL;
361 }
362
363 /* end of plugin_gnsrecord_credential.c */