58be7853bed10c0a286c21e6c497a053dbe2a234
[oweals/gnunet.git] / src / credential / gnunet-service-credential.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2011-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  * @file gns/gnunet-service-credential.c
22  * @brief GNU Credential Service (main service)
23  * @author Adnan Husain 
24  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_credential_service.h"
28 #include "gnunet_statistics_service.h"
29 #include "credential.h"
30 #include "gnunet_protocols.h"
31
32 // For Looking up GNS request
33 #include <gnunet_dnsparser_lib.h>
34 #include <gnunet_identity_service.h>
35 #include <gnunet_gnsrecord_lib.h>
36 #include <gnunet_namestore_service.h>
37 #include <gnunet_gns_service.h>
38 #include "gnunet_gns_service.h"
39
40
41
42
43 #define GNUNET_CREDENTIAL_MAX_LENGTH 255
44
45 /**
46  * DLL for record
47  */
48 struct AttributeRecordEntry
49 {
50   /**
51    * DLL
52    */
53   struct AttributeRecordEntry *next;
54
55   /**
56    * DLL
57    */
58   struct AttributeRecordEntry *prev;
59
60
61   /**
62    * Payload
63    */
64   struct GNUNET_CREDENTIAL_AttributeRecordData record_data;
65 };
66
67 /**
68  * Handle to a lookup operation from api
69  */
70 struct VerifyRequestHandle
71 {
72
73   /**
74    * We keep these in a DLL.
75    */
76   struct VerifyRequestHandle *next;
77
78   /**
79    * We keep these in a DLL.
80    */
81   struct VerifyRequestHandle *prev;
82
83   /**
84    * Handle to the requesting client
85    */
86   struct GNUNET_SERVICE_Client *client;
87
88   /**
89    * Handle to GNS lookup
90    */
91   struct GNUNET_GNS_LookupRequest *lookup_request;
92
93   /**
94    * Issuer public key
95    */
96   struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
97
98   /**
99    * Subject public key
100    */
101   struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
102
103   /**
104    * Attribute Chain
105    */
106   struct AttributeRecordEntry *attr_chain_head;
107
108   /**
109    * Attribute Chain
110    */
111   struct AttributeRecordEntry *attr_chain_tail;
112
113   /**
114    * request id
115    */
116   uint32_t request_id;
117
118 };
119
120
121 /**
122  * Head of the DLL.
123  */
124 static struct VerifyRequestHandle *vrh_head;
125
126 /**
127  * Tail of the DLL.
128  */
129 static struct VerifyRequestHandle *vrh_tail;
130
131 /**
132  * Handle to the statistics service
133  */
134 static struct GNUNET_STATISTICS_Handle *statistics;
135
136
137
138 /**
139  * Handle to GNS service.
140  */
141 static struct GNUNET_GNS_Handle *gns;
142
143 /**
144  * Task run during shutdown.
145  *
146  * @param cls unused
147  * @param tc unused
148  */
149 static void
150 shutdown_task (void *cls)
151 {
152   struct VerifyRequestHandle *vrh;
153   
154   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155               "Shutting down!\n");
156   while (NULL != (vrh = vrh_head))
157   {
158     //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
159     GNUNET_CONTAINER_DLL_remove (vrh_head,
160                                  vrh_tail,
161                                  vrh);
162     GNUNET_free (vrh);
163   }
164
165   
166   if (NULL != statistics)
167   {
168     GNUNET_STATISTICS_destroy (statistics,
169                                GNUNET_NO);
170     statistics = NULL;
171   }
172   
173 }
174
175 /**
176  * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
177  *
178  * @param cls client sending the message
179  * @param v_msg message of type `struct VerifyMessage`
180  * @return #GNUNET_OK if @a v_msg is well-formed
181  */
182 static int
183 check_verify (void *cls,
184                     const struct VerifyMessage *v_msg)
185 {
186   size_t msg_size;
187   size_t attr_len;
188   const char* s_attr;
189   const char* i_attr;
190
191   msg_size = ntohs (v_msg->header.size);
192   if (msg_size < sizeof (struct VerifyMessage))
193   {
194     GNUNET_break (0);
195     return GNUNET_SYSERR;
196   }
197   i_attr = (const char *) &v_msg[1];
198   if ( ('\0' != i_attr[v_msg->header.size - sizeof (struct VerifyMessage) - 1]) ||
199        (strlen (i_attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
200   {
201     GNUNET_break (0);
202     return GNUNET_SYSERR;
203   }
204   attr_len = strlen (i_attr);
205   s_attr = ((const char *) &v_msg[1]) + attr_len + 1;
206   if ( ('\0' != s_attr[v_msg->header.size - sizeof (struct VerifyMessage) - 1]) ||
207        (strlen (s_attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
208   {
209     GNUNET_break (0);
210     return GNUNET_SYSERR;
211   }
212   return GNUNET_OK;
213 }
214
215
216 /**
217  * Result from GNS lookup.
218  *
219  * @param cls the closure (our client lookup handle)
220  * @param rd_count the number of records in @a rd
221  * @param rd the record data
222  */
223 static void
224 send_lookup_response (void* cls,
225                       uint32_t rd_count,
226                       const struct GNUNET_GNSRECORD_Data *rd)
227 {
228   struct VerifyRequestHandle *vrh = cls;
229   size_t len;
230   int i;
231   int attr_record_count;
232   struct GNUNET_MQ_Envelope *env;
233   struct VerifyResultMessage *rmsg;
234   const struct GNUNET_CREDENTIAL_AttributeRecordData *ard;
235   struct AttributeRecordEntry *ar_entry;
236
237   attr_record_count = 0;
238   for (i=0; i < rd_count; i++)
239   {
240     if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type)
241       continue;
242     attr_record_count++;
243     ard = rd[i].data;
244     /**
245      * TODO:
246      * Check if we have already found our credential here
247      * If so return success
248      * Else
249      *  Save all found attributes/issues and prepare forward
250      *  resolution of issuer attribute
251      */
252     ar_entry = GNUNET_new (struct AttributeRecordEntry);
253     ar_entry->record_data = *ard;
254     GNUNET_CONTAINER_DLL_insert_tail (vrh->attr_chain_head,
255                                       vrh->attr_chain_tail,
256                                       ar_entry);
257
258   }
259
260   /**
261    * Get serialized record data size
262    */
263   len = attr_record_count * sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData);
264
265   /**
266    * Prepare a lookup result response message for the client
267    */
268   env = GNUNET_MQ_msg_extra (rmsg,
269                              len,
270                              GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
271   //Assign id so that client can find associated request
272   rmsg->id = vrh->request_id;
273   rmsg->ad_count = htonl (attr_record_count);
274
275   /**
276    * Get serialized record data
277    * Append at the end of rmsg
278    */
279   i = 0;
280   struct GNUNET_CREDENTIAL_AttributeRecordData *tmp_record = (struct GNUNET_CREDENTIAL_AttributeRecordData*) &rmsg[1];
281   for (ar_entry = vrh->attr_chain_head; NULL != ar_entry; ar_entry = ar_entry->next)
282   {
283     memcpy (tmp_record,
284             &ar_entry->record_data,
285             sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData));
286     tmp_record++;
287   }
288   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
289                   env);
290
291   GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
292
293   /**
294    * TODO:
295    * - Free DLL
296    * - Refactor into cleanup_handle() function for this
297    */
298   GNUNET_free (vrh);
299
300   GNUNET_STATISTICS_update (statistics,
301                             "Completed verifications", 1,
302                             GNUNET_NO);
303   GNUNET_STATISTICS_update (statistics,
304                             "Attributes resolved",
305                             rd_count,
306                             GNUNET_NO);
307 }
308
309 /**
310  * Handle attribute verification requests from client
311  *
312  * @param cls the closure
313  * @param client the client
314  * @param message the message
315  */
316 static void
317 handle_verify (void *cls,
318                const struct VerifyMessage *v_msg) 
319 {
320   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
321   char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
322   size_t issuer_attribute_len;
323   struct VerifyRequestHandle *vrh;
324   struct GNUNET_SERVICE_Client *client = cls;
325   char *attrptr = issuer_attribute;
326   const char *utf_in;
327
328   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
329               "Received VERIFY message\n");
330
331   utf_in = (const char *) &v_msg[1];
332   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
333   issuer_attribute_len = strlen (utf_in);
334   utf_in = (const char *) (&v_msg[1] + issuer_attribute_len + 1);
335   attrptr = subject_attribute;
336   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
337   vrh = GNUNET_new (struct VerifyRequestHandle);
338   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
339   vrh->client = client;
340   vrh->request_id = v_msg->id;
341   vrh->issuer_key = v_msg->issuer_key;
342   vrh->subject_key = v_msg->subject_key;
343
344   if (NULL == subject_attribute)
345   {
346     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
347                 "No subject attribute provided!\n");
348     send_lookup_response (vrh, 0, NULL);
349     return;
350   }
351   if (NULL == issuer_attribute)
352   {
353     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
354                 "No issuer attribute provided!\n");
355     send_lookup_response (vrh, 0, NULL);
356     return;
357   }
358   /**
359    * First, get attribute from subject
360    */
361   vrh->lookup_request = GNUNET_GNS_lookup (gns,
362                                            subject_attribute,
363                                            &v_msg->subject_key, //subject_pkey,
364                                            GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
365                                            GNUNET_GNS_LO_DEFAULT,
366                                            NULL, //shorten_key, always NULL
367                                            &send_lookup_response,
368                                            vrh);
369 }
370
371
372 /**
373  * One of our clients disconnected, clean up after it.
374  *
375  * @param cls NULL
376  * @param client the client that disconnected
377  */
378 static void
379 client_disconnect_cb (void *cls,
380                       struct GNUNET_SERVICE_Client *client,
381                       void *app_ctx)
382 {
383   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
384               "Client %p disconnected\n",
385               client);
386 }
387
388 /**
389  * Add a client to our list of active clients.
390  *
391  * @param cls NULL
392  * @param client client to add
393  * @param mq message queue for @a client
394  * @return this client
395  */
396 static void *
397 client_connect_cb (void *cls,
398                    struct GNUNET_SERVICE_Client *client,
399                    struct GNUNET_MQ_Handle *mq)
400 {
401   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402               "Client %p connected\n",
403               client);
404   return client;
405 }
406
407 /**
408  * Process Credential requests.
409  *
410  * @param cls closure
411  * @param server the initialized server
412  * @param c configuration to use
413  */
414 static void
415 run (void *cls,
416      const struct GNUNET_CONFIGURATION_Handle *c,
417      struct GNUNET_SERVICE_Handle *handle)
418 {
419
420   gns = GNUNET_GNS_connect (c);
421   if (NULL == gns)
422   {
423     fprintf (stderr,
424              _("Failed to connect to GNS\n"));
425   }
426
427   statistics = GNUNET_STATISTICS_create ("credential", c);
428   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
429 }
430
431
432 /**
433  * Define "main" method using service macro
434  */
435 GNUNET_SERVICE_MAIN
436 ("credential",
437  GNUNET_SERVICE_OPTION_NONE,
438  &run,
439  &client_connect_cb,
440  &client_disconnect_cb,
441  NULL,
442  GNUNET_MQ_hd_var_size (verify,
443                         GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
444                         struct VerifyMessage,
445                         NULL),
446  GNUNET_MQ_handler_end());
447
448 /* end of gnunet-service-credential.c */