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