3ad2e2e1dd580c057e72569d00e2f529c47fd9a9
[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    * TODO
262    * Start resolution of Attribute delegations from issuer
263    *
264    * - Build adequate data structures for attribute(s) to lookup
265    * - Use GNUNET_GNSRECORD_TYPE_XXX
266    * - recursively try to find match(es) with results found top
267    * - return one found credential chain
268    *
269    */
270
271   /**
272    * Get serialized record data size
273    */
274   len = attr_record_count * sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData);
275
276   /**
277    * Prepare a lookup result response message for the client
278    */
279   env = GNUNET_MQ_msg_extra (rmsg,
280                              len,
281                              GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
282   //Assign id so that client can find associated request
283   rmsg->id = vrh->request_id;
284   rmsg->ad_count = htonl (attr_record_count);
285
286   /**
287    * Get serialized record data
288    * Append at the end of rmsg
289    */
290   i = 0;
291   struct GNUNET_CREDENTIAL_AttributeRecordData *tmp_record = (struct GNUNET_CREDENTIAL_AttributeRecordData*) &rmsg[1];
292   for (ar_entry = vrh->attr_chain_head; NULL != ar_entry; ar_entry = ar_entry->next)
293   {
294     memcpy (tmp_record,
295             &ar_entry->record_data,
296             sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData));
297     tmp_record++;
298   }
299   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
300                   env);
301
302   GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
303
304   /**
305    * TODO:
306    * - Free DLL
307    * - Refactor into cleanup_handle() function for this
308    */
309   GNUNET_free (vrh);
310
311   GNUNET_STATISTICS_update (statistics,
312                             "Completed verifications", 1,
313                             GNUNET_NO);
314   GNUNET_STATISTICS_update (statistics,
315                             "Attributes resolved",
316                             rd_count,
317                             GNUNET_NO);
318 }
319
320 /**
321  * Handle attribute verification requests from client
322  *
323  * @param cls the closure
324  * @param client the client
325  * @param message the message
326  */
327 static void
328 handle_verify (void *cls,
329                const struct VerifyMessage *v_msg) 
330 {
331   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
332   char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
333   size_t issuer_attribute_len;
334   struct VerifyRequestHandle *vrh;
335   struct GNUNET_SERVICE_Client *client = cls;
336   char *attrptr = issuer_attribute;
337   const char *utf_in;
338
339   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
340               "Received VERIFY message\n");
341
342   utf_in = (const char *) &v_msg[1];
343   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
344   issuer_attribute_len = strlen (utf_in);
345   utf_in = (const char *) (&v_msg[1] + issuer_attribute_len + 1);
346   attrptr = subject_attribute;
347   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
348   vrh = GNUNET_new (struct VerifyRequestHandle);
349   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
350   vrh->client = client;
351   vrh->request_id = v_msg->id;
352   vrh->issuer_key = v_msg->issuer_key;
353   vrh->subject_key = v_msg->subject_key;
354
355   if (NULL == subject_attribute)
356   {
357     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
358                 "No subject attribute provided!\n");
359     send_lookup_response (vrh, 0, NULL);
360     return;
361   }
362   if (NULL == issuer_attribute)
363   {
364     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
365                 "No issuer attribute provided!\n");
366     send_lookup_response (vrh, 0, NULL);
367     return;
368   }
369   /**
370    * First, get attribute from subject
371    */
372   vrh->lookup_request = GNUNET_GNS_lookup (gns,
373                                            subject_attribute,
374                                            &v_msg->subject_key, //subject_pkey,
375                                            GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
376                                            GNUNET_GNS_LO_DEFAULT,
377                                            NULL, //shorten_key, always NULL
378                                            &send_lookup_response,
379                                            vrh);
380 }
381
382
383 /**
384  * One of our clients disconnected, clean up after it.
385  *
386  * @param cls NULL
387  * @param client the client that disconnected
388  */
389 static void
390 client_disconnect_cb (void *cls,
391                       struct GNUNET_SERVICE_Client *client,
392                       void *app_ctx)
393 {
394   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
395               "Client %p disconnected\n",
396               client);
397 }
398
399 /**
400  * Add a client to our list of active clients.
401  *
402  * @param cls NULL
403  * @param client client to add
404  * @param mq message queue for @a client
405  * @return this client
406  */
407 static void *
408 client_connect_cb (void *cls,
409                    struct GNUNET_SERVICE_Client *client,
410                    struct GNUNET_MQ_Handle *mq)
411 {
412   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
413               "Client %p connected\n",
414               client);
415   return client;
416 }
417
418 /**
419  * Process Credential requests.
420  *
421  * @param cls closure
422  * @param server the initialized server
423  * @param c configuration to use
424  */
425 static void
426 run (void *cls,
427      const struct GNUNET_CONFIGURATION_Handle *c,
428      struct GNUNET_SERVICE_Handle *handle)
429 {
430
431   gns = GNUNET_GNS_connect (c);
432   if (NULL == gns)
433   {
434     fprintf (stderr,
435              _("Failed to connect to GNS\n"));
436   }
437
438   statistics = GNUNET_STATISTICS_create ("credential", c);
439   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
440 }
441
442
443 /**
444  * Define "main" method using service macro
445  */
446 GNUNET_SERVICE_MAIN
447 ("credential",
448  GNUNET_SERVICE_OPTION_NONE,
449  &run,
450  &client_connect_cb,
451  &client_disconnect_cb,
452  NULL,
453  GNUNET_MQ_hd_var_size (verify,
454                         GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
455                         struct VerifyMessage,
456                         NULL),
457  GNUNET_MQ_handler_end());
458
459 /* end of gnunet-service-credential.c */