Merge branch 'master' into credentials
[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 CredentialRecordEntry
49 {
50   /**
51    * DLL
52    */
53   struct CredentialRecordEntry *next;
54
55   /**
56    * DLL
57    */
58   struct CredentialRecordEntry *prev;
59
60
61   /**
62    * Payload
63    */
64   struct GNUNET_CREDENTIAL_RecordData record_data;
65 };
66
67 /**
68  * Handle to a lookup operation from api
69  */
70 struct ClientLookupHandle
71 {
72
73   /**
74    * We keep these in a DLL.
75    */
76   struct ClientLookupHandle *next;
77
78   /**
79    * We keep these in a DLL.
80    */
81   struct ClientLookupHandle *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    * Authority public key
95    */
96   struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
97
98   /**
99    * Credential Chain
100    */
101   struct CredentialRecordEntry *cred_chain_head;
102
103   /**
104    * Credential Chain
105    */
106   struct CredentialRecordEntry *cred_chain_tail;
107
108   /**
109    * request id
110    */
111   uint32_t request_id;
112
113 };
114
115
116 /**
117  * Head of the DLL.
118  */
119 static struct ClientLookupHandle *clh_head;
120
121 /**
122  * Tail of the DLL.
123  */
124 static struct ClientLookupHandle *clh_tail;
125
126 /**
127  * Handle to the statistics service
128  */
129 static struct GNUNET_STATISTICS_Handle *statistics;
130
131
132
133 /**
134  * Handle to GNS service.
135  */
136 static struct GNUNET_GNS_Handle *gns;
137
138 /**
139  * Task run during shutdown.
140  *
141  * @param cls unused
142  * @param tc unused
143  */
144 static void
145 shutdown_task (void *cls)
146 {
147   struct ClientLookupHandle *clh;
148   
149   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150               "Shutting down!\n");
151   while (NULL != (clh = clh_head))
152   {
153     //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
154     GNUNET_CONTAINER_DLL_remove (clh_head,
155                                  clh_tail,
156                                  clh);
157     GNUNET_free (clh);
158   }
159
160   
161   if (NULL != statistics)
162   {
163     GNUNET_STATISTICS_destroy (statistics,
164                                GNUNET_NO);
165     statistics = NULL;
166   }
167   
168 }
169
170 /**
171  * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_LOOKUP message
172  *
173  * @param cls client sending the message
174  * @param l_msg message of type `struct LookupMessage`
175  * @return #GNUNET_OK if @a l_msg is well-formed
176  */
177 static int
178 check_lookup (void *cls,
179                     const struct LookupMessage *l_msg)
180 {
181   size_t msg_size;
182   const char* cred;
183
184   msg_size = ntohs (l_msg->header.size);
185   if (msg_size < sizeof (struct LookupMessage))
186   {
187     GNUNET_break (0);
188     return GNUNET_SYSERR;
189   }
190   cred = (const char *) &l_msg[1];
191   if ( ('\0' != cred[l_msg->header.size - sizeof (struct LookupMessage) - 1]) ||
192        (strlen (cred) > GNUNET_CREDENTIAL_MAX_LENGTH) )
193   {
194     GNUNET_break (0);
195     return GNUNET_SYSERR;
196   }
197   return GNUNET_OK;
198 }
199
200
201 /**
202  * Reply to client with the result from our lookup.
203  *
204  * @param cls the closure (our client lookup handle)
205  * @param rd_count the number of records in @a rd
206  * @param rd the record data
207  */
208 static void
209 send_lookup_response (void* cls,
210                       uint32_t rd_count,
211                       const struct GNUNET_GNSRECORD_Data *rd)
212 {
213   struct ClientLookupHandle *clh = cls;
214   size_t len;
215   int i;
216   int cred_record_count;
217   struct GNUNET_MQ_Envelope *env;
218   struct LookupResultMessage *rmsg;
219   const struct GNUNET_CREDENTIAL_RecordData *crd;
220   struct CredentialRecordEntry *cr_entry;
221
222   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
223               "Sending LOOKUP_RESULT message with %u results\n",
224               (unsigned int) rd_count);
225   
226   cred_record_count = 0;
227   for (i=0; i < rd_count; i++)
228   {
229     if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
230       continue;
231     cred_record_count++;
232     crd = rd[i].data;
233     /**
234      * TODO: Check for:
235      * - First time we come here subject must be subject prvided by client
236      * - After that is has to be the prev issuer
237      * - Terminate condition: issuer is clh->authority_key
238      *
239      *   In any case:
240      *   Append crd to result list of RecordData
241      */
242     cr_entry = GNUNET_new (struct CredentialRecordEntry);
243     cr_entry->record_data = *crd;
244     GNUNET_CONTAINER_DLL_insert_tail (clh->cred_chain_head,
245                                       clh->cred_chain_tail,
246                                       cr_entry);
247
248   }
249
250   /**
251    * Get serialized record data size
252    */
253   len = cred_record_count * sizeof (struct GNUNET_CREDENTIAL_RecordData);
254   
255   /**
256    * Prepare a lookup result response message for the client
257    */
258   env = GNUNET_MQ_msg_extra (rmsg,
259                              len,
260                              GNUNET_MESSAGE_TYPE_CREDENTIAL_LOOKUP_RESULT);
261   //Assign id so that client can find associated request
262   rmsg->id = clh->request_id;
263   rmsg->cd_count = htonl (cred_record_count);
264   
265   /**
266    * Get serialized record data
267    * Append at the end of rmsg
268    */
269   i = 0;
270   struct GNUNET_CREDENTIAL_RecordData *tmp_record = (struct GNUNET_CREDENTIAL_RecordData*) &rmsg[1];
271   for (cr_entry = clh->cred_chain_head; NULL != cr_entry; cr_entry = cr_entry->next)
272   {
273     memcpy (tmp_record,
274             &cr_entry->record_data,
275             sizeof (struct GNUNET_CREDENTIAL_RecordData));
276     tmp_record++;
277   }
278   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(clh->client),
279                   env);
280
281   GNUNET_CONTAINER_DLL_remove (clh_head, clh_tail, clh);
282   
283   /**
284    * TODO:
285    * - Free DLL
286    * - Refactor into cleanup_handle() function for this
287    */
288   GNUNET_free (clh);
289
290   GNUNET_STATISTICS_update (statistics,
291                             "Completed lookups", 1,
292                             GNUNET_NO);
293   GNUNET_STATISTICS_update (statistics,
294                             "Records resolved",
295                             rd_count,
296                             GNUNET_NO);
297 }
298
299 /**
300  * Handle lookup requests from client
301  *
302  * @param cls the closure
303  * @param client the client
304  * @param message the message
305  */
306 static void
307 handle_lookup (void *cls,
308                const struct LookupMessage *l_msg) 
309 {
310   char credential[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
311   struct ClientLookupHandle *clh;
312   struct GNUNET_SERVICE_Client *client = cls;
313   char *credentialptr = credential;
314   const char *utf_in;
315
316   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317               "Received LOOKUP message\n");
318
319   utf_in = (const char *) &l_msg[1];
320   GNUNET_STRINGS_utf8_tolower (utf_in, credentialptr);
321   clh = GNUNET_new (struct ClientLookupHandle);
322   GNUNET_CONTAINER_DLL_insert (clh_head, clh_tail, clh);
323   clh->client = client;
324   clh->request_id = l_msg->id;
325   clh->issuer_key = l_msg->issuer_key;
326
327   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
328               "Sending LOOKUP_RESULT message with >%u results\n",
329               0);
330
331   if (NULL == credential)
332   {
333     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
334                 "No credential provided\n");
335     send_lookup_response (clh, 0, NULL);
336     return;
337   }
338   clh->lookup_request = GNUNET_GNS_lookup (gns,
339                                            credential,
340                                            &l_msg->subject_key, //subject_pkey,
341                                            GNUNET_GNSRECORD_TYPE_CREDENTIAL,
342                                            GNUNET_GNS_LO_DEFAULT, //TODO configurable? credential.conf
343                                            NULL, //shorten_key, always NULL
344                                            &send_lookup_response,
345                                            clh);
346 }
347
348
349 /**
350  * One of our clients disconnected, clean up after it.
351  *
352  * @param cls NULL
353  * @param client the client that disconnected
354  */
355 static void
356 client_disconnect_cb (void *cls,
357                       struct GNUNET_SERVICE_Client *client,
358                       void *app_ctx)
359 {
360   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
361               "Client %p disconnected\n",
362               client);
363 }
364
365 /**
366  * Add a client to our list of active clients.
367  *
368  * @param cls NULL
369  * @param client client to add
370  * @param mq message queue for @a client
371  * @return this client
372  */
373 static void *
374 client_connect_cb (void *cls,
375                    struct GNUNET_SERVICE_Client *client,
376                    struct GNUNET_MQ_Handle *mq)
377 {
378   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
379               "Client %p connected\n",
380               client);
381   return client;
382 }
383
384 /**
385  * Process Credential requests.
386  *
387  * @param cls closure
388  * @param server the initialized server
389  * @param c configuration to use
390  */
391 static void
392 run (void *cls,
393      const struct GNUNET_CONFIGURATION_Handle *c,
394      struct GNUNET_SERVICE_Handle *handle)
395 {
396
397   gns = GNUNET_GNS_connect (c);
398   if (NULL == gns)
399   {
400     fprintf (stderr,
401              _("Failed to connect to GNS\n"));
402   }
403
404   statistics = GNUNET_STATISTICS_create ("credential", c);
405   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
406 }
407
408
409 /**
410  * Define "main" method using service macro
411  */
412 GNUNET_SERVICE_MAIN
413 ("credential",
414  GNUNET_SERVICE_OPTION_NONE,
415  &run,
416  &client_connect_cb,
417  &client_disconnect_cb,
418  NULL,
419  GNUNET_MQ_hd_var_size (lookup,
420                         GNUNET_MESSAGE_TYPE_CREDENTIAL_LOOKUP,
421                         struct LookupMessage,
422                         NULL),
423  GNUNET_MQ_handler_end());
424
425 /* end of gnunet-service-credential.c */