-change api
[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 Adnan Husain
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     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_ERROR,
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    default:
129    return NULL;
130   }
131 }
132
133
134 /**
135  * Convert human-readable version of a 'value' of a record to the binary
136  * representation.
137  *
138  * @param cls closure, unused
139  * @param type type of the record
140  * @param s human-readable string
141  * @param data set to value in binary encoding (will be allocated)
142  * @param data_size set to number of bytes in @a data
143  * @return #GNUNET_OK on success
144  */
145 static int
146 credential_string_to_value (void *cls,
147                             uint32_t type,
148                             const char *s,
149                             void **data,
150                             size_t *data_size)
151 {
152   if (NULL == s)
153     return GNUNET_SYSERR;
154   switch (type)
155   {
156     case GNUNET_GNSRECORD_TYPE_ATTRIBUTE:
157       {
158         struct GNUNET_CREDENTIAL_DelegationRecord *sets;
159         char attr_str[253 + 1];
160         char subject_pkey[52 + 1];
161         char *token;
162         char *tmp_str;
163         int matches = 0;
164         int entries;
165         size_t tmp_data_size;
166         int i;
167
168         tmp_str = GNUNET_strdup (s);
169         token = strtok (tmp_str, ",");
170         entries = 0;
171         tmp_data_size = 0;
172         *data_size = sizeof (struct GNUNET_CREDENTIAL_DelegationRecord);
173         while (NULL != token)
174         {
175           matches = SSCANF (token,
176                             "%s %s",
177                             subject_pkey,
178                             attr_str);
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           if (1 == matches) {
188             tmp_data_size += sizeof (struct GNUNET_CREDENTIAL_DelegationRecordSet);
189           } else if (2 == matches) {
190             tmp_data_size += sizeof (struct GNUNET_CREDENTIAL_DelegationRecordSet) + strlen (attr_str) + 1;
191           }
192           entries++;
193           token = strtok (NULL, ",");
194         }
195         GNUNET_free (tmp_str);
196         tmp_str = GNUNET_strdup (s);
197         token = strtok (tmp_str, ",");
198         struct GNUNET_CREDENTIAL_DelegationSet set[entries];
199         for (i=0;i<entries;i++)
200         {
201           matches = SSCANF (token,
202                             "%s %s",
203                             subject_pkey,
204                             attr_str);
205           GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_pkey,
206                                                       strlen (subject_pkey),
207                                                       &set[i].subject_key);
208           if (2 == matches) {
209             set[i].subject_attribute_len = strlen (attr_str) + 1;
210             set[i].subject_attribute = GNUNET_strdup (attr_str);
211           }
212           token = strtok (NULL , ",");
213         }
214         tmp_data_size = GNUNET_CREDENTIAL_delegation_set_get_size (entries,
215                                                                    set);
216         
217         if (-1 == tmp_data_size)
218           return GNUNET_SYSERR;
219         *data_size += tmp_data_size;
220         *data = sets = GNUNET_malloc (*data_size);
221         GNUNET_CREDENTIAL_delegation_set_serialize (entries,
222                                                     set,
223                                                     tmp_data_size,
224                                                     (char*)&sets[1]);
225         for (i=0;i<entries;i++)
226         {
227           if (0 != set[i].subject_attribute_len)
228             GNUNET_free ((char*)set[i].subject_attribute);
229         }
230         sets->set_count = htonl (entries);
231         sets->data_size = GNUNET_htonll (tmp_data_size);
232
233         GNUNET_free (tmp_str);
234         return GNUNET_OK;
235       }
236     case GNUNET_GNSRECORD_TYPE_CREDENTIAL:
237       { 
238         struct GNUNET_CREDENTIAL_Credential *cred;
239         cred = GNUNET_CREDENTIAL_credential_from_string (s);
240
241         *data_size = GNUNET_CREDENTIAL_credential_serialize (cred,
242                                                              (char**)data);
243         return GNUNET_OK;
244       }
245     default:
246       return GNUNET_SYSERR;
247   }
248 }
249
250
251 /**
252  * Mapping of record type numbers to human-readable
253  * record type names.
254  */
255 static struct {
256   const char *name;
257   uint32_t number;
258 } name_map[] = {
259   { "CRED", GNUNET_GNSRECORD_TYPE_CREDENTIAL },
260   { "ATTR", GNUNET_GNSRECORD_TYPE_ATTRIBUTE },
261   { NULL, UINT32_MAX }
262 };
263
264
265 /**
266  * Convert a type name (i.e. "AAAA") to the corresponding number.
267  *
268  * @param cls closure, unused
269  * @param gns_typename name to convert
270  * @return corresponding number, UINT32_MAX on error
271  */
272 static uint32_t
273 credential_typename_to_number (void *cls,
274                                const char *gns_typename)
275 {
276   unsigned int i;
277
278   i=0;
279   while ( (name_map[i].name != NULL) &&
280           (0 != strcasecmp (gns_typename, name_map[i].name)) )
281     i++;
282   return name_map[i].number;
283 }
284
285
286 /**
287  * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
288  *
289  * @param cls closure, unused
290  * @param type number of a type to convert
291  * @return corresponding typestring, NULL on error
292  */
293 static const char *
294 credential_number_to_typename (void *cls,
295                                uint32_t type)
296 {
297   unsigned int i;
298
299   i=0;
300   while ( (name_map[i].name != NULL) &&
301           (type != name_map[i].number) )
302     i++;
303   return name_map[i].name;
304 }
305
306
307 /**
308  * Entry point for the plugin.
309  *
310  * @param cls NULL
311  * @return the exported block API
312  */
313 void *
314 libgnunet_plugin_gnsrecord_credential_init (void *cls)
315 {
316   struct GNUNET_GNSRECORD_PluginFunctions *api;
317
318   api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
319   api->value_to_string = &credential_value_to_string;
320   api->string_to_value = &credential_string_to_value;
321   api->typename_to_number = &credential_typename_to_number;
322   api->number_to_typename = &credential_number_to_typename;
323   return api;
324 }
325
326
327 /**
328  * Exit point from the plugin.
329  *
330  * @param cls the return value from #libgnunet_plugin_block_test_init
331  * @return NULL
332  */
333 void *
334 libgnunet_plugin_gnsrecord_credential_done (void *cls)
335 {
336   struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
337
338   GNUNET_free (api);
339   return NULL;
340 }
341
342 /* end of plugin_gnsrecord_credential.c */