remove 'illegal' (non-reentrant) log logic from signal handler
[oweals/gnunet.git] / src / identity / plugin_rest_identity.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 GNUnet e.V.
4
5    GNUnet is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your 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    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @author Martin Schanzenbach
22  * @author Philippe Buschmann
23  * @file identity/plugin_rest_identity.c
24  * @brief GNUnet Identity REST plugin
25  */
26
27 #include "platform.h"
28 #include "gnunet_rest_plugin.h"
29 #include "gnunet_identity_service.h"
30 #include "gnunet_rest_lib.h"
31 #include "microhttpd.h"
32 #include <jansson.h>
33
34 /**
35  * Identity Namespace
36  */
37 #define GNUNET_REST_API_NS_IDENTITY "/identity"
38
39 /**
40  * Identity Namespace with public key specifier
41  */
42 #define GNUNET_REST_API_NS_IDENTITY_PUBKEY "/identity/pubkey"
43
44 /**
45  * Identity Namespace with public key specifier
46  */
47 #define GNUNET_REST_API_NS_IDENTITY_NAME "/identity/name"
48
49 /**
50  * Identity Subsystem Namespace
51  */
52 #define GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM "/identity/subsystem"
53
54 /**
55  * Parameter public key
56  */
57 #define GNUNET_REST_IDENTITY_PARAM_PUBKEY "pubkey"
58
59 /**
60  * Parameter subsystem
61  */
62 #define GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM "subsystem"
63
64 /**
65  * Parameter name
66  */
67 #define GNUNET_REST_IDENTITY_PARAM_NAME "name"
68
69 /**
70  * Parameter new name
71  */
72 #define GNUNET_REST_IDENTITY_PARAM_NEWNAME "newname"
73
74 /**
75  * Error message Unknown Error
76  */
77 #define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error"
78
79 /**
80  * Error message No identity found
81  */
82 #define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found"
83
84 /**
85  * Error message Missing identity name
86  */
87 #define GNUNET_REST_IDENTITY_MISSING_NAME "Missing identity name"
88
89 /**
90  * Error message Missing identity name
91  */
92 #define GNUNET_REST_IDENTITY_MISSING_PUBKEY "Missing identity public key"
93
94 /**
95  * Error message No data
96  */
97 #define GNUNET_REST_ERROR_NO_DATA "No data"
98
99 /**
100  * Error message Data invalid
101  */
102 #define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
103
104 /**
105  * State while collecting all egos
106  */
107 #define ID_REST_STATE_INIT 0
108
109 /**
110  * Done collecting egos
111  */
112 #define ID_REST_STATE_POST_INIT 1
113
114 /**
115  * The configuration handle
116  */
117 const struct GNUNET_CONFIGURATION_Handle *cfg;
118
119 /**
120  * HTTP methods allows for this plugin
121  */
122 static char *allow_methods;
123
124 /**
125  * @brief struct returned by the initialization function of the plugin
126  */
127 struct Plugin
128 {
129   const struct GNUNET_CONFIGURATION_Handle *cfg;
130 };
131
132 /**
133  * The ego list
134  */
135 struct EgoEntry
136 {
137   /**
138    * DLL
139    */
140   struct EgoEntry *next;
141
142   /**
143    * DLL
144    */
145   struct EgoEntry *prev;
146
147   /**
148    * Ego Identifier
149    */
150   char *identifier;
151
152   /**
153    * Public key string
154    */
155   char *keystring;
156
157   /**
158    * The Ego
159    */
160   struct GNUNET_IDENTITY_Ego *ego;
161 };
162
163 /**
164  * The request handle
165  */
166 struct RequestHandle
167 {
168   /**
169    * The data from the REST request
170    */
171   const char *data;
172
173   /**
174    * The name to look up
175    */
176   char *name;
177
178   /**
179    * the length of the REST data
180    */
181   size_t data_size;
182
183
184   /**
185    * Ego list
186    */
187   struct EgoEntry *ego_head;
188
189   /**
190    * Ego list
191    */
192   struct EgoEntry *ego_tail;
193
194   /**
195    * The processing state
196    */
197   int state;
198
199   /**
200    * Handle to Identity service.
201    */
202   struct GNUNET_IDENTITY_Handle *identity_handle;
203
204   /**
205    * IDENTITY Operation
206    */
207   struct GNUNET_IDENTITY_Operation *op;
208
209   /**
210    * Rest connection
211    */
212   struct GNUNET_REST_RequestHandle *rest_handle;
213
214   /**
215    * Desired timeout for the lookup (default is no timeout).
216    */
217   struct GNUNET_TIME_Relative timeout;
218
219   /**
220    * ID of a task associated with the resolution process.
221    */
222   struct GNUNET_SCHEDULER_Task *timeout_task;
223
224   /**
225    * The plugin result processor
226    */
227   GNUNET_REST_ResultProcessor proc;
228
229   /**
230    * The closure of the result processor
231    */
232   void *proc_cls;
233
234   /**
235    * The url
236    */
237   char *url;
238
239   /**
240    * Error response message
241    */
242   char *emsg;
243
244   /**
245    * Response code
246    */
247   int response_code;
248 };
249
250 /**
251  * Cleanup lookup handle
252  * @param handle Handle to clean up
253  */
254 static void
255 cleanup_handle (void *cls)
256 {
257   struct RequestHandle *handle = cls;
258   struct EgoEntry *ego_entry;
259   struct EgoEntry *ego_tmp;
260
261   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
262   if (NULL != handle->timeout_task)
263   {
264     GNUNET_SCHEDULER_cancel (handle->timeout_task);
265     handle->timeout_task = NULL;
266   }
267
268   if (NULL != handle->url)
269     GNUNET_free (handle->url);
270   if (NULL != handle->emsg)
271     GNUNET_free (handle->emsg);
272   if (NULL != handle->name)
273     GNUNET_free (handle->name);
274   if (NULL != handle->identity_handle)
275     GNUNET_IDENTITY_disconnect (handle->identity_handle);
276
277   for (ego_entry = handle->ego_head; NULL != ego_entry;)
278   {
279     ego_tmp = ego_entry;
280     ego_entry = ego_entry->next;
281     GNUNET_free (ego_tmp->identifier);
282     GNUNET_free (ego_tmp->keystring);
283     GNUNET_free (ego_tmp);
284   }
285
286   GNUNET_free (handle);
287 }
288
289
290 /**
291  * Task run on errors.  Reports an error and cleans up everything.
292  *
293  * @param cls the `struct RequestHandle`
294  */
295 static void
296 do_error (void *cls)
297 {
298   struct RequestHandle *handle = cls;
299   struct MHD_Response *resp;
300   json_t *json_error = json_object ();
301   char *response;
302
303   if (NULL == handle->emsg)
304     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_ERROR_UNKNOWN);
305
306   json_object_set_new (json_error, "error", json_string (handle->emsg));
307
308   if (0 == handle->response_code)
309     handle->response_code = MHD_HTTP_OK;
310   response = json_dumps (json_error, 0);
311   resp = GNUNET_REST_create_response (response);
312   handle->proc (handle->proc_cls, resp, handle->response_code);
313   json_decref (json_error);
314   GNUNET_free (response);
315   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
316 }
317
318
319 /**
320  * Get EgoEntry from list with either a public key or a name
321  * If public key and name are not NULL, it returns the public key result first
322  *
323  * @param handle the RequestHandle
324  * @param pubkey the public key of an identity (only one can be NULL)
325  * @param name the name of an identity (only one can be NULL)
326  * @return EgoEntry or NULL if not found
327  */
328 struct EgoEntry *
329 get_egoentry (struct RequestHandle *handle, char *pubkey, char *name)
330 {
331   struct EgoEntry *ego_entry;
332
333   if (NULL != pubkey)
334   {
335     for (ego_entry = handle->ego_head; NULL != ego_entry;
336          ego_entry = ego_entry->next)
337     {
338       if (0 != strcasecmp (pubkey, ego_entry->keystring))
339         continue;
340       return ego_entry;
341     }
342   }
343   if (NULL != name)
344   {
345     for (ego_entry = handle->ego_head; NULL != ego_entry;
346          ego_entry = ego_entry->next)
347     {
348       if (0 != strcasecmp (name, ego_entry->identifier))
349         continue;
350       return ego_entry;
351     }
352   }
353   return NULL;
354 }
355
356
357 /**
358  * Callback for GET Request with subsystem
359  *
360  * @param cls the RequestHandle
361  * @param ego the Ego found
362  * @param ctx the context
363  * @param name the id of the ego
364  */
365 static void
366 ego_get_for_subsystem (void *cls,
367                        struct GNUNET_IDENTITY_Ego *ego,
368                        void **ctx,
369                        const char *name)
370 {
371   struct RequestHandle *handle = cls;
372   struct MHD_Response *resp;
373   struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
374   json_t *json_root;
375   char *result_str;
376   char *public_key_string;
377
378   if (NULL == ego)
379   {
380     handle->response_code = MHD_HTTP_NOT_FOUND;
381     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
382     GNUNET_SCHEDULER_add_now (&do_error, handle);
383     return;
384   }
385
386   GNUNET_IDENTITY_ego_get_public_key (ego, &public_key);
387   public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string (&public_key);
388
389   // create json with subsystem identity
390   json_root = json_object ();
391   json_object_set_new (json_root,
392                        GNUNET_REST_IDENTITY_PARAM_PUBKEY,
393                        json_string (public_key_string));
394   json_object_set_new (json_root,
395                        GNUNET_REST_IDENTITY_PARAM_NAME,
396                        json_string (name));
397
398   result_str = json_dumps (json_root, 0);
399   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
400   resp = GNUNET_REST_create_response (result_str);
401
402   json_decref (json_root);
403   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
404   GNUNET_free (result_str);
405   GNUNET_free (public_key_string);
406   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
407 }
408
409
410 /**
411  * Handle identity GET request for subsystem
412  *
413  * @param con_handle the connection handle
414  * @param url the url
415  * @param cls the RequestHandle
416  */
417 void
418 ego_get_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
419                    const char *url,
420                    void *cls)
421 {
422   struct RequestHandle *handle = cls;
423   char *subsystem;
424
425   if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
426   {
427     handle->emsg = GNUNET_strdup ("Missing subsystem name");
428     GNUNET_SCHEDULER_add_now (&do_error, handle);
429     return;
430   }
431   subsystem = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1];
432   // requested default identity of subsystem
433   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsystem);
434
435   handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
436                                     subsystem,
437                                     &ego_get_for_subsystem,
438                                     handle);
439
440   if (NULL == handle->op)
441   {
442     handle->response_code = MHD_HTTP_NOT_FOUND;
443     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
444     GNUNET_SCHEDULER_add_now (&do_error, handle);
445     return;
446   }
447 }
448
449
450 /**
451  * Handle identity GET request - responds with all identities
452  *
453  * @param con_handle the connection handle
454  * @param url the url
455  * @param cls the RequestHandle
456  */
457 void
458 ego_get_all (struct GNUNET_REST_RequestHandle *con_handle,
459              const char *url,
460              void *cls)
461 {
462   struct RequestHandle *handle = cls;
463   struct EgoEntry *ego_entry;
464   struct MHD_Response *resp;
465   json_t *json_root;
466   json_t *json_ego;
467   char *result_str;
468
469   json_root = json_array ();
470   // Return ego/egos
471   for (ego_entry = handle->ego_head; NULL != ego_entry;
472        ego_entry = ego_entry->next)
473   {
474     json_ego = json_object ();
475     json_object_set_new (json_ego,
476                          GNUNET_REST_IDENTITY_PARAM_PUBKEY,
477                          json_string (ego_entry->keystring));
478     json_object_set_new (json_ego,
479                          GNUNET_REST_IDENTITY_PARAM_NAME,
480                          json_string (ego_entry->identifier));
481     json_array_append (json_root, json_ego);
482     json_decref (json_ego);
483   }
484
485   result_str = json_dumps (json_root, 0);
486   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
487   resp = GNUNET_REST_create_response (result_str);
488
489   json_decref (json_root);
490   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
491   GNUNET_free (result_str);
492   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
493 }
494
495
496 /**
497  * Responds with the ego_entry identity
498  *
499  * @param handle the struct RequestHandle
500  * @param ego_entry the struct EgoEntry for the response
501  */
502 void
503 ego_get_response (struct RequestHandle *handle, struct EgoEntry *ego_entry)
504 {
505   struct MHD_Response *resp;
506   json_t *json_ego;
507   char *result_str;
508
509   json_ego = json_object ();
510   json_object_set_new (json_ego,
511                        GNUNET_REST_IDENTITY_PARAM_PUBKEY,
512                        json_string (ego_entry->keystring));
513   json_object_set_new (json_ego,
514                        GNUNET_REST_IDENTITY_PARAM_NAME,
515                        json_string (ego_entry->identifier));
516
517   result_str = json_dumps (json_ego, 0);
518   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
519   resp = GNUNET_REST_create_response (result_str);
520   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
521
522   json_decref (json_ego);
523   GNUNET_free (result_str);
524   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
525 }
526
527
528 /**
529  * Handle identity GET request with a public key
530  *
531  * @param con_handle the connection handle
532  * @param url the url
533  * @param cls the RequestHandle
534  */
535 void
536 ego_get_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
537                 const char *url,
538                 void *cls)
539 {
540   struct RequestHandle *handle = cls;
541   struct EgoEntry *ego_entry;
542   char *keystring;
543
544   keystring = NULL;
545
546   if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
547   {
548     handle->response_code = MHD_HTTP_NOT_FOUND;
549     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_PUBKEY);
550     GNUNET_SCHEDULER_add_now (&do_error, handle);
551     return;
552   }
553   keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1];
554   ego_entry = get_egoentry (handle, keystring, NULL);
555
556   if (NULL == ego_entry)
557   {
558     handle->response_code = MHD_HTTP_NOT_FOUND;
559     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
560     GNUNET_SCHEDULER_add_now (&do_error, handle);
561     return;
562   }
563
564   ego_get_response (handle, ego_entry);
565 }
566
567
568 /**
569  * Handle identity GET request with a name
570  *
571  * @param con_handle the connection handle
572  * @param url the url
573  * @param cls the RequestHandle
574  */
575 void
576 ego_get_name (struct GNUNET_REST_RequestHandle *con_handle,
577               const char *url,
578               void *cls)
579 {
580   struct RequestHandle *handle = cls;
581   struct EgoEntry *ego_entry;
582   char *egoname;
583
584   egoname = NULL;
585
586   if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
587   {
588     handle->response_code = MHD_HTTP_NOT_FOUND;
589     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_NAME);
590     GNUNET_SCHEDULER_add_now (&do_error, handle);
591     return;
592   }
593   egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1];
594   ego_entry = get_egoentry (handle, NULL, egoname);
595
596   if (NULL == ego_entry)
597   {
598     handle->response_code = MHD_HTTP_NOT_FOUND;
599     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
600     GNUNET_SCHEDULER_add_now (&do_error, handle);
601     return;
602   }
603
604   ego_get_response (handle, ego_entry);
605 }
606
607
608 /**
609  * Processing finished
610  *
611  * @param cls request handle
612  * @param emsg error message
613  */
614 static void
615 do_finished (void *cls, const char *emsg)
616 {
617   struct RequestHandle *handle = cls;
618   struct MHD_Response *resp;
619
620   handle->op = NULL;
621   if (NULL != emsg)
622   {
623     handle->emsg = GNUNET_strdup (emsg);
624     GNUNET_SCHEDULER_add_now (&do_error, handle);
625     return;
626   }
627   if (0 == handle->response_code)
628   {
629     handle->response_code = MHD_HTTP_NO_CONTENT;
630   }
631   resp = GNUNET_REST_create_response (NULL);
632   handle->proc (handle->proc_cls, resp, handle->response_code);
633   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
634 }
635
636
637 /**
638  * Processing finished, when creating an ego.
639  *
640  * @param cls request handle
641  * @param private key of the ego, or NULL on error
642  * @param emsg error message
643  */
644 static void
645 do_finished_create (void *cls,
646                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
647                     const char *emsg)
648 {
649   struct RequestHandle *handle = cls;
650
651   (void) pk;
652   do_finished (handle, emsg);
653 }
654
655
656 /**
657  * Processing edit ego with EgoEntry ego_entry
658  *
659  * @param handle the struct RequestHandle
660  * @param ego_entry the struct EgoEntry we want to edit
661  */
662 void
663 ego_edit (struct RequestHandle *handle, struct EgoEntry *ego_entry)
664 {
665   struct EgoEntry *ego_entry_tmp;
666   struct MHD_Response *resp;
667   json_t *data_js;
668   json_error_t err;
669   char *newname;
670   char term_data[handle->data_size + 1];
671   int json_state;
672
673   // if no data
674   if (0 >= handle->data_size)
675   {
676     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
677     GNUNET_SCHEDULER_add_now (&do_error, handle);
678     return;
679   }
680   // if not json
681   term_data[handle->data_size] = '\0';
682   GNUNET_memcpy (term_data, handle->data, handle->data_size);
683   data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
684
685   if (NULL == data_js)
686   {
687     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
688     GNUNET_SCHEDULER_add_now (&do_error, handle);
689     return;
690   }
691
692   newname = NULL;
693   // NEW NAME
694   json_state = 0;
695   json_state = json_unpack (data_js,
696                             "{s:s!}",
697                             GNUNET_REST_IDENTITY_PARAM_NEWNAME,
698                             &newname);
699   // Change name with pubkey or name identifier
700   if (0 != json_state)
701   {
702     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
703     GNUNET_SCHEDULER_add_now (&do_error, handle);
704     json_decref (data_js);
705     return;
706   }
707
708   if (NULL == newname)
709   {
710     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
711     GNUNET_SCHEDULER_add_now (&do_error, handle);
712     json_decref (data_js);
713     return;
714   }
715
716   if (0 >= strlen (newname))
717   {
718     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
719     GNUNET_SCHEDULER_add_now (&do_error, handle);
720     json_decref (data_js);
721     return;
722   }
723
724   ego_entry_tmp = get_egoentry (handle, NULL, newname);
725   if (NULL != ego_entry_tmp)
726   {
727     // Ego with same name not allowed (even if its the ego we change)
728     resp = GNUNET_REST_create_response (NULL);
729     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
730     GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
731     json_decref (data_js);
732     return;
733   }
734   handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
735                                        ego_entry->identifier,
736                                        newname,
737                                        &do_finished,
738                                        handle);
739   if (NULL == handle->op)
740   {
741     handle->emsg = GNUNET_strdup ("Rename failed");
742     GNUNET_SCHEDULER_add_now (&do_error, handle);
743     json_decref (data_js);
744     return;
745   }
746   json_decref (data_js);
747   return;
748 }
749
750
751 /**
752  * Handle identity PUT request with public key
753  *
754  * @param con_handle the connection handle
755  * @param url the url
756  * @param cls the RequestHandle
757  */
758 void
759 ego_edit_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
760                  const char *url,
761                  void *cls)
762 {
763   struct RequestHandle *handle = cls;
764   struct EgoEntry *ego_entry;
765   char *keystring;
766
767   keystring = NULL;
768
769   if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
770   {
771     handle->response_code = MHD_HTTP_NOT_FOUND;
772     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_PUBKEY);
773     GNUNET_SCHEDULER_add_now (&do_error, handle);
774     return;
775   }
776   keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1];
777   ego_entry = get_egoentry (handle, keystring, NULL);
778
779   if (NULL == ego_entry)
780   {
781     handle->response_code = MHD_HTTP_NOT_FOUND;
782     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
783     GNUNET_SCHEDULER_add_now (&do_error, handle);
784     return;
785   }
786
787   ego_edit (handle, ego_entry);
788 }
789
790
791 /**
792  * Handle identity PUT request with name
793  *
794  * @param con_handle the connection handle
795  * @param url the url
796  * @param cls the RequestHandle
797  */
798 void
799 ego_edit_name (struct GNUNET_REST_RequestHandle *con_handle,
800                const char *url,
801                void *cls)
802 {
803   struct RequestHandle *handle = cls;
804   struct EgoEntry *ego_entry;
805   char *name;
806
807   name = NULL;
808
809   if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
810   {
811     handle->response_code = MHD_HTTP_NOT_FOUND;
812     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_NAME);
813     GNUNET_SCHEDULER_add_now (&do_error, handle);
814     return;
815   }
816   name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1];
817   ego_entry = get_egoentry (handle, NULL, name);
818
819   if (NULL == ego_entry)
820   {
821     handle->response_code = MHD_HTTP_NOT_FOUND;
822     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
823     GNUNET_SCHEDULER_add_now (&do_error, handle);
824     return;
825   }
826
827   ego_edit (handle, ego_entry);
828 }
829
830
831 /**
832  * Handle identity subsystem PUT request with name
833  *
834  * @param con_handle the connection handle
835  * @param url the url
836  * @param cls the RequestHandle
837  */
838 void
839 ego_edit_subsystem (struct GNUNET_REST_RequestHandle *con_handle,
840                     const char *url,
841                     void *cls)
842 {
843   struct RequestHandle *handle = cls;
844   struct EgoEntry *ego_entry;
845   json_t *data_js;
846   json_error_t err;
847   char *newsubsys;
848   char *name;
849   char term_data[handle->data_size + 1];
850   int json_state;
851
852   name = NULL;
853
854   if (strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) >= strlen (handle->url))
855   {
856     handle->response_code = MHD_HTTP_NOT_FOUND;
857     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_NAME);
858     GNUNET_SCHEDULER_add_now (&do_error, handle);
859     return;
860   }
861   name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM) + 1];
862   ego_entry = get_egoentry (handle, NULL, name);
863
864   if (NULL == ego_entry)
865   {
866     handle->response_code = MHD_HTTP_NOT_FOUND;
867     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
868     GNUNET_SCHEDULER_add_now (&do_error, handle);
869     return;
870   }
871
872   // if no data
873   if (0 >= handle->data_size)
874   {
875     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
876     GNUNET_SCHEDULER_add_now (&do_error, handle);
877     return;
878   }
879   // if not json
880   term_data[handle->data_size] = '\0';
881   GNUNET_memcpy (term_data, handle->data, handle->data_size);
882   data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
883
884   if (NULL == data_js)
885   {
886     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
887     GNUNET_SCHEDULER_add_now (&do_error, handle);
888     return;
889   }
890
891   newsubsys = NULL;
892   // SUBSYSTEM
893   json_state = 0;
894   json_state = json_unpack (data_js,
895                             "{s:s!}",
896                             GNUNET_REST_IDENTITY_PARAM_SUBSYSTEM,
897                             &newsubsys);
898   // Change subsystem with pubkey or name identifier
899   if (0 != json_state)
900   {
901     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
902     GNUNET_SCHEDULER_add_now (&do_error, handle);
903     json_decref (data_js);
904     return;
905   }
906
907   if (NULL == newsubsys)
908   {
909     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
910     GNUNET_SCHEDULER_add_now (&do_error, handle);
911     json_decref (data_js);
912     return;
913   }
914
915   if (0 >= strlen (newsubsys))
916   {
917     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
918     GNUNET_SCHEDULER_add_now (&do_error, handle);
919     json_decref (data_js);
920     return;
921   }
922
923   handle->response_code = MHD_HTTP_NO_CONTENT;
924   handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
925                                     newsubsys,
926                                     ego_entry->ego,
927                                     &do_finished,
928                                     handle);
929   if (NULL == handle->op)
930   {
931     handle->emsg = GNUNET_strdup ("Setting subsystem failed");
932     GNUNET_SCHEDULER_add_now (&do_error, handle);
933     return;
934   }
935   json_decref (data_js);
936   return;
937 }
938
939
940 /**
941  * Handle identity POST request
942  *
943  * @param con_handle the connection handle
944  * @param url the url
945  * @param cls the RequestHandle
946  */
947 void
948 ego_create (struct GNUNET_REST_RequestHandle *con_handle,
949             const char *url,
950             void *cls)
951 {
952   struct RequestHandle *handle = cls;
953   struct EgoEntry *ego_entry;
954   struct MHD_Response *resp;
955   json_t *data_js;
956   json_error_t err;
957   char *egoname;
958   int json_unpack_state;
959   char term_data[handle->data_size + 1];
960
961   if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
962   {
963     GNUNET_SCHEDULER_add_now (&do_error, handle);
964     return;
965   }
966
967   if (0 >= handle->data_size)
968   {
969     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
970     GNUNET_SCHEDULER_add_now (&do_error, handle);
971     return;
972   }
973   term_data[handle->data_size] = '\0';
974   GNUNET_memcpy (term_data, handle->data, handle->data_size);
975   data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
976   if (NULL == data_js)
977   {
978     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
979     GNUNET_SCHEDULER_add_now (&do_error, handle);
980     json_decref (data_js);
981     return;
982   }
983   json_unpack_state = 0;
984   json_unpack_state =
985     json_unpack (data_js, "{s:s!}", GNUNET_REST_IDENTITY_PARAM_NAME, &egoname);
986   if (0 != json_unpack_state)
987   {
988     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
989     GNUNET_SCHEDULER_add_now (&do_error, handle);
990     json_decref (data_js);
991     return;
992   }
993
994   if (NULL == egoname)
995   {
996     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
997     GNUNET_SCHEDULER_add_now (&do_error, handle);
998     json_decref (data_js);
999     return;
1000   }
1001   if (0 >= strlen (egoname))
1002   {
1003     json_decref (data_js);
1004     handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
1005     GNUNET_SCHEDULER_add_now (&do_error, handle);
1006     return;
1007   }
1008   GNUNET_STRINGS_utf8_tolower (egoname, egoname);
1009   for (ego_entry = handle->ego_head; NULL != ego_entry;
1010        ego_entry = ego_entry->next)
1011   {
1012     if (0 == strcasecmp (egoname, ego_entry->identifier))
1013     {
1014       resp = GNUNET_REST_create_response (NULL);
1015       handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1016       GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1017       json_decref (data_js);
1018       return;
1019     }
1020   }
1021   handle->name = GNUNET_strdup (egoname);
1022   json_decref (data_js);
1023   handle->response_code = MHD_HTTP_CREATED;
1024   handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
1025                                        handle->name,
1026                                        &do_finished_create,
1027                                        handle);
1028 }
1029
1030
1031 /**
1032  * Handle identity DELETE request with public key
1033  *
1034  * @param con_handle the connection handle
1035  * @param url the url
1036  * @param cls the RequestHandle
1037  */
1038 void
1039 ego_delete_pubkey (struct GNUNET_REST_RequestHandle *con_handle,
1040                    const char *url,
1041                    void *cls)
1042 {
1043   struct RequestHandle *handle = cls;
1044   struct EgoEntry *ego_entry;
1045   char *keystring;
1046
1047   keystring = NULL;
1048
1049   if (strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) >= strlen (handle->url))
1050   {
1051     handle->response_code = MHD_HTTP_NOT_FOUND;
1052     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_PUBKEY);
1053     GNUNET_SCHEDULER_add_now (&do_error, handle);
1054     return;
1055   }
1056   keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_PUBKEY) + 1];
1057   ego_entry = get_egoentry (handle, keystring, NULL);
1058
1059   if (NULL == ego_entry)
1060   {
1061     handle->response_code = MHD_HTTP_NOT_FOUND;
1062     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
1063     GNUNET_SCHEDULER_add_now (&do_error, handle);
1064     return;
1065   }
1066
1067   handle->response_code = MHD_HTTP_NO_CONTENT;
1068   handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1069                                        ego_entry->identifier,
1070                                        &do_finished,
1071                                        handle);
1072 }
1073
1074
1075 /**
1076  * Handle identity DELETE request with name
1077  *
1078  * @param con_handle the connection handle
1079  * @param url the url
1080  * @param cls the RequestHandle
1081  */
1082 void
1083 ego_delete_name (struct GNUNET_REST_RequestHandle *con_handle,
1084                  const char *url,
1085                  void *cls)
1086 {
1087   struct RequestHandle *handle = cls;
1088   struct EgoEntry *ego_entry;
1089   char *name;
1090
1091   name = NULL;
1092
1093   if (strlen (GNUNET_REST_API_NS_IDENTITY_NAME) >= strlen (handle->url))
1094   {
1095     handle->response_code = MHD_HTTP_NOT_FOUND;
1096     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_MISSING_NAME);
1097     GNUNET_SCHEDULER_add_now (&do_error, handle);
1098     return;
1099   }
1100   name = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY_NAME) + 1];
1101   ego_entry = get_egoentry (handle, NULL, name);
1102
1103   if (NULL == ego_entry)
1104   {
1105     handle->response_code = MHD_HTTP_NOT_FOUND;
1106     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
1107     GNUNET_SCHEDULER_add_now (&do_error, handle);
1108     return;
1109   }
1110
1111   handle->response_code = MHD_HTTP_NO_CONTENT;
1112   handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
1113                                        ego_entry->identifier,
1114                                        &do_finished,
1115                                        handle);
1116 }
1117
1118
1119 /**
1120  * Respond to OPTIONS request
1121  *
1122  * @param con_handle the connection handle
1123  * @param url the url
1124  * @param cls the RequestHandle
1125  */
1126 static void
1127 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1128               const char *url,
1129               void *cls)
1130 {
1131   struct MHD_Response *resp;
1132   struct RequestHandle *handle = cls;
1133
1134   // For now, independent of path return all options
1135   resp = GNUNET_REST_create_response (NULL);
1136   MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1137   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1138   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
1139   return;
1140 }
1141
1142
1143 /**
1144  * Handle rest request
1145  *
1146  * @param handle the request handle
1147  */
1148 static void
1149 init_cont (struct RequestHandle *handle)
1150 {
1151   struct GNUNET_REST_RequestHandlerError err;
1152   static const struct GNUNET_REST_RequestHandler handlers[] =
1153   { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_get_all },
1154     { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PUBKEY,
1155       &ego_get_pubkey },
1156     { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_get_name },
1157     { MHD_HTTP_METHOD_GET,
1158       GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM,
1159       &ego_get_subsystem },
1160     { MHD_HTTP_METHOD_PUT,
1161       GNUNET_REST_API_NS_IDENTITY_PUBKEY,
1162       &ego_edit_pubkey },
1163     { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY_NAME, &ego_edit_name },
1164     { MHD_HTTP_METHOD_PUT,
1165       GNUNET_REST_API_NS_IDENTITY_SUBSYSTEM,
1166       &ego_edit_subsystem },
1167     { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create },
1168     { MHD_HTTP_METHOD_DELETE,
1169       GNUNET_REST_API_NS_IDENTITY_PUBKEY,
1170       &ego_delete_pubkey },
1171     { MHD_HTTP_METHOD_DELETE,
1172       GNUNET_REST_API_NS_IDENTITY_NAME,
1173       &ego_delete_name },
1174     { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont },
1175     GNUNET_REST_HANDLER_END };
1176
1177   if (GNUNET_NO ==
1178       GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1179   {
1180     handle->response_code = err.error_code;
1181     GNUNET_SCHEDULER_add_now (&do_error, handle);
1182   }
1183 }
1184
1185
1186 /**
1187  * If listing is enabled, prints information about the egos.
1188  *
1189  * This function is initially called for all egos and then again
1190  * whenever a ego's identifier changes or if it is deleted.  At the
1191  * end of the initial pass over all egos, the function is once called
1192  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1193  * be invoked in the future or that there was an error.
1194  *
1195  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1196  * this function is only called ONCE, and 'NULL' being passed in
1197  * 'ego' does indicate an error (i.e. name is taken or no default
1198  * value is known).  If 'ego' is non-NULL and if '*ctx'
1199  * is set in those callbacks, the value WILL be passed to a subsequent
1200  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1201  * that one was not NULL).
1202  *
1203  * When an identity is renamed, this function is called with the
1204  * (known) ego but the NEW identifier.
1205  *
1206  * When an identity is deleted, this function is called with the
1207  * (known) ego and "NULL" for the 'identifier'.  In this case,
1208  * the 'ego' is henceforth invalid (and the 'ctx' should also be
1209  * cleaned up).
1210  *
1211  * @param cls closure
1212  * @param ego ego handle
1213  * @param ctx context for application to store data for this ego
1214  *                 (during the lifetime of this process, initially NULL)
1215  * @param identifier identifier assigned by the user for this ego,
1216  *                   NULL if the user just deleted the ego and it
1217  *                   must thus no longer be used
1218  */
1219 static void
1220 init_egos (void *cls,
1221            struct GNUNET_IDENTITY_Ego *ego,
1222            void **ctx,
1223            const char *identifier)
1224 {
1225   struct RequestHandle *handle = cls;
1226   struct EgoEntry *ego_entry;
1227   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1228
1229   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1230   {
1231     handle->state = ID_REST_STATE_POST_INIT;
1232     init_cont (handle);
1233     return;
1234   }
1235   if (ID_REST_STATE_INIT == handle->state)
1236   {
1237     ego_entry = GNUNET_new (struct EgoEntry);
1238     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1239     ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1240     ego_entry->ego = ego;
1241     ego_entry->identifier = GNUNET_strdup (identifier);
1242     GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1243                                       handle->ego_tail,
1244                                       ego_entry);
1245     return;
1246   }
1247   // Check if ego exists
1248   for (ego_entry = handle->ego_head; NULL != ego_entry;)
1249   {
1250     struct EgoEntry *tmp = ego_entry;
1251     ego_entry = ego_entry->next;
1252     if (ego != tmp->ego)
1253       continue;
1254     // Deleted
1255     if (NULL == identifier)
1256     {
1257       GNUNET_CONTAINER_DLL_remove (handle->ego_head,
1258                                    handle->ego_tail,
1259                                    tmp);
1260       GNUNET_free (tmp->keystring);
1261       GNUNET_free (tmp->identifier);
1262       GNUNET_free (tmp);
1263     }
1264     else
1265     {
1266       // Renamed
1267       GNUNET_free (tmp->identifier);
1268       tmp->identifier = GNUNET_strdup (identifier);
1269     }
1270     return;
1271   }
1272   // New ego
1273   ego_entry = GNUNET_new (struct EgoEntry);
1274   GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1275   ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1276   ego_entry->ego = ego;
1277   GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
1278   GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1279                                     handle->ego_tail,
1280                                     ego_entry);
1281
1282 }
1283
1284
1285 /**
1286  * Function processing the REST call
1287  *
1288  * @param method HTTP method
1289  * @param url URL of the HTTP request
1290  * @param data body of the HTTP request (optional)
1291  * @param data_size length of the body
1292  * @param proc callback function for the result
1293  * @param proc_cls closure for callback function
1294  * @return GNUNET_OK if request accepted
1295  */
1296 static void
1297 rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1298                       GNUNET_REST_ResultProcessor proc,
1299                       void *proc_cls)
1300 {
1301   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1302
1303   handle->response_code = 0;
1304   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1305   handle->proc_cls = proc_cls;
1306   handle->proc = proc;
1307   handle->rest_handle = rest_handle;
1308   handle->data = rest_handle->data;
1309   handle->data_size = rest_handle->data_size;
1310
1311   handle->url = GNUNET_strdup (rest_handle->url);
1312   if (handle->url[strlen (handle->url) - 1] == '/')
1313     handle->url[strlen (handle->url) - 1] = '\0';
1314   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1315
1316   handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle);
1317
1318   handle->timeout_task =
1319     GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
1320
1321   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1322 }
1323
1324
1325 /**
1326  * Entry point for the plugin.
1327  *
1328  * @param cls Config info
1329  * @return NULL on error, otherwise the plugin context
1330  */
1331 void *
1332 libgnunet_plugin_rest_identity_init (void *cls)
1333 {
1334   static struct Plugin plugin;
1335   struct GNUNET_REST_Plugin *api;
1336
1337   cfg = cls;
1338   if (NULL != plugin.cfg)
1339     return NULL; /* can only initialize once! */
1340   memset (&plugin, 0, sizeof(struct Plugin));
1341   plugin.cfg = cfg;
1342   api = GNUNET_new (struct GNUNET_REST_Plugin);
1343   api->cls = &plugin;
1344   api->name = GNUNET_REST_API_NS_IDENTITY;
1345   api->process_request = &rest_process_request;
1346   GNUNET_asprintf (&allow_methods,
1347                    "%s, %s, %s, %s, %s",
1348                    MHD_HTTP_METHOD_GET,
1349                    MHD_HTTP_METHOD_POST,
1350                    MHD_HTTP_METHOD_PUT,
1351                    MHD_HTTP_METHOD_DELETE,
1352                    MHD_HTTP_METHOD_OPTIONS);
1353
1354   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Identity REST API initialized\n"));
1355   return api;
1356 }
1357
1358
1359 /**
1360  * Exit point from the plugin.
1361  *
1362  * @param cls the plugin context (as returned by "init")
1363  * @return always NULL
1364  */
1365 void *
1366 libgnunet_plugin_rest_identity_done (void *cls)
1367 {
1368   struct GNUNET_REST_Plugin *api = cls;
1369   struct Plugin *plugin = api->cls;
1370
1371   plugin->cfg = NULL;
1372
1373   GNUNET_free_non_null (allow_methods);
1374   GNUNET_free (api);
1375   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n");
1376   return NULL;
1377 }
1378
1379
1380 /* end of plugin_rest_identity.c */