Style fixes (mostly tabs to spaces).
[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     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         struct GNUNET_CREDENTIAL_DelegationSet set[entries];
203         for (i=0;i<entries;i++)
204         {
205           matches = SSCANF (token,
206                             "%s %s",
207                             subject_pkey,
208                             attr_str);
209           GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_pkey,
210                                                       strlen (subject_pkey),
211                                                       &set[i].subject_key);
212           if (2 == matches) {
213             set[i].subject_attribute_len = strlen (attr_str) + 1;
214             set[i].subject_attribute = GNUNET_strdup (attr_str);
215           }
216           token = strtok (NULL , ",");
217         }
218         tmp_data_size = GNUNET_CREDENTIAL_delegation_set_get_size (entries,
219                                                                    set);
220         
221         if (-1 == tmp_data_size)
222           return GNUNET_SYSERR;
223         *data_size += tmp_data_size;
224         *data = sets = GNUNET_malloc (*data_size);
225         GNUNET_CREDENTIAL_delegation_set_serialize (entries,
226                                                     set,
227                                                     tmp_data_size,
228                                                     (char*)&sets[1]);
229         for (i=0;i<entries;i++)
230         {
231           if (0 != set[i].subject_attribute_len)
232             GNUNET_free ((char*)set[i].subject_attribute);
233         }
234         sets->set_count = htonl (entries);
235         sets->data_size = GNUNET_htonll (tmp_data_size);
236
237         GNUNET_free (tmp_str);
238         return GNUNET_OK;
239       }
240     case GNUNET_GNSRECORD_TYPE_CREDENTIAL:
241       { 
242         struct GNUNET_CREDENTIAL_Credential *cred;
243         cred = GNUNET_CREDENTIAL_credential_from_string (s);
244
245         *data_size = GNUNET_CREDENTIAL_credential_serialize (cred,
246                                                              (char**)data);
247         return GNUNET_OK;
248       }
249     case GNUNET_GNSRECORD_TYPE_POLICY:
250       {
251         *data_size = strlen (s);
252         *data = GNUNET_strdup (s);
253         return GNUNET_OK;
254       }
255     default:
256       return GNUNET_SYSERR;
257   }
258 }
259
260
261 /**
262  * Mapping of record type numbers to human-readable
263  * record type names.
264  */
265 static struct {
266   const char *name;
267   uint32_t number;
268 } name_map[] = {
269   { "CRED", GNUNET_GNSRECORD_TYPE_CREDENTIAL },
270   { "ATTR", GNUNET_GNSRECORD_TYPE_ATTRIBUTE },
271   { "POLICY", GNUNET_GNSRECORD_TYPE_POLICY },
272   { NULL, UINT32_MAX }
273 };
274
275
276 /**
277  * Convert a type name (i.e. "AAAA") to the corresponding number.
278  *
279  * @param cls closure, unused
280  * @param gns_typename name to convert
281  * @return corresponding number, UINT32_MAX on error
282  */
283 static uint32_t
284 credential_typename_to_number (void *cls,
285                                const char *gns_typename)
286 {
287   unsigned int i;
288
289   i=0;
290   while ( (name_map[i].name != NULL) &&
291           (0 != strcasecmp (gns_typename, name_map[i].name)) )
292     i++;
293   return name_map[i].number;
294 }
295
296
297 /**
298  * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
299  *
300  * @param cls closure, unused
301  * @param type number of a type to convert
302  * @return corresponding typestring, NULL on error
303  */
304 static const char *
305 credential_number_to_typename (void *cls,
306                                uint32_t type)
307 {
308   unsigned int i;
309
310   i=0;
311   while ( (name_map[i].name != NULL) &&
312           (type != name_map[i].number) )
313     i++;
314   return name_map[i].name;
315 }
316
317
318 /**
319  * Entry point for the plugin.
320  *
321  * @param cls NULL
322  * @return the exported block API
323  */
324 void *
325 libgnunet_plugin_gnsrecord_credential_init (void *cls)
326 {
327   struct GNUNET_GNSRECORD_PluginFunctions *api;
328
329   api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
330   api->value_to_string = &credential_value_to_string;
331   api->string_to_value = &credential_string_to_value;
332   api->typename_to_number = &credential_typename_to_number;
333   api->number_to_typename = &credential_number_to_typename;
334   return api;
335 }
336
337
338 /**
339  * Exit point from the plugin.
340  *
341  * @param cls the return value from #libgnunet_plugin_block_test_init
342  * @return NULL
343  */
344 void *
345 libgnunet_plugin_gnsrecord_credential_done (void *cls)
346 {
347   struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
348
349   GNUNET_free (api);
350   return NULL;
351 }
352
353 /* end of plugin_gnsrecord_credential.c */