get rid of plain memcpy calls
[oweals/gnunet.git] / src / identity-provider / identity_provider_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2016 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 Liceidentity 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 Liceidentity for more details.
14
15      You should have received a copy of the GNU General Public Liceidentity
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 identity-provider/identity_provider_api.c
23  * @brief api to interact with the identity provider service
24  * @author Martin Schanzenbach
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_mq_lib.h"
31 #include "gnunet_identity_provider_service.h"
32 #include "gnunet_identity_attribute_lib.h"
33 #include "identity_provider.h"
34
35 #define LOG(kind,...) GNUNET_log_from (kind, "identity-api",__VA_ARGS__)
36
37
38 /**
39  * Handle for an operation with the service.
40  */
41 struct GNUNET_IDENTITY_PROVIDER_Operation
42 {
43
44   /**
45    * Main handle.
46    */
47   struct GNUNET_IDENTITY_PROVIDER_Handle *h;
48
49   /**
50    * We keep operations in a DLL.
51    */
52   struct GNUNET_IDENTITY_PROVIDER_Operation *next;
53
54   /**
55    * We keep operations in a DLL.
56    */
57   struct GNUNET_IDENTITY_PROVIDER_Operation *prev;
58
59   /**
60    * Message to send to the service.
61    * Allocated at the end of this struct.
62    */
63   const struct GNUNET_MessageHeader *msg;
64
65   /**
66    * Continuation to invoke after attribute store call
67    */
68   GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus as_cb;
69
70   /**
71    * Attribute result callback
72    */
73   GNUNET_IDENTITY_PROVIDER_AttributeResult ar_cb;
74
75   /**
76    * Revocation result callback
77    */
78   GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus rvk_cb;
79
80   /**
81    * Ticket result callback
82    */
83   GNUNET_IDENTITY_PROVIDER_TicketCallback tr_cb;
84
85   /**
86    * Envelope with the message for this queue entry.
87    */
88   struct GNUNET_MQ_Envelope *env;
89
90   /**
91    * request id
92    */
93   uint32_t r_id;
94
95   /**
96    * Closure for @e cont or @e cb.
97    */
98   void *cls;
99
100 };
101
102 /**
103  * Handle for a ticket iterator operation
104  */
105 struct GNUNET_IDENTITY_PROVIDER_TicketIterator
106 {
107
108   /**
109    * Kept in a DLL.
110    */
111   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *next;
112
113   /**
114    * Kept in a DLL.
115    */
116   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *prev;
117
118   /**
119    * Main handle to access the idp.
120    */
121   struct GNUNET_IDENTITY_PROVIDER_Handle *h;
122
123   /**
124    * Function to call on completion.
125    */
126   GNUNET_SCHEDULER_TaskCallback finish_cb;
127
128   /**
129    * Closure for @e error_cb.
130    */
131   void *finish_cb_cls;
132
133   /**
134    * The continuation to call with the results
135    */
136   GNUNET_IDENTITY_PROVIDER_TicketCallback tr_cb;
137
138   /**
139    * Closure for @e tr_cb.
140    */
141   void *cls;
142
143   /**
144    * Function to call on errors.
145    */
146   GNUNET_SCHEDULER_TaskCallback error_cb;
147
148   /**
149    * Closure for @e error_cb.
150    */
151   void *error_cb_cls;
152
153   /**
154    * Envelope of the message to send to the service, if not yet
155    * sent.
156    */
157   struct GNUNET_MQ_Envelope *env;
158
159   /**
160    * The operation id this zone iteration operation has
161    */
162   uint32_t r_id;
163
164 };
165
166
167 /**
168  * Handle for a attribute iterator operation
169  */
170 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator
171 {
172
173   /**
174    * Kept in a DLL.
175    */
176   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *next;
177
178   /**
179    * Kept in a DLL.
180    */
181   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *prev;
182
183   /**
184    * Main handle to access the idp.
185    */
186   struct GNUNET_IDENTITY_PROVIDER_Handle *h;
187
188   /**
189    * Function to call on completion.
190    */
191   GNUNET_SCHEDULER_TaskCallback finish_cb;
192
193   /**
194    * Closure for @e error_cb.
195    */
196   void *finish_cb_cls;
197
198   /**
199    * The continuation to call with the results
200    */
201   GNUNET_IDENTITY_PROVIDER_AttributeResult proc;
202
203   /**
204    * Closure for @e proc.
205    */
206   void *proc_cls;
207
208   /**
209    * Function to call on errors.
210    */
211   GNUNET_SCHEDULER_TaskCallback error_cb;
212
213   /**
214    * Closure for @e error_cb.
215    */
216   void *error_cb_cls;
217
218   /**
219    * Envelope of the message to send to the service, if not yet
220    * sent.
221    */
222   struct GNUNET_MQ_Envelope *env;
223
224   /**
225    * Private key of the zone.
226    */
227   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
228
229   /**
230    * The operation id this zone iteration operation has
231    */
232   uint32_t r_id;
233
234 };
235
236
237 /**
238  * Handle for the service.
239  */
240 struct GNUNET_IDENTITY_PROVIDER_Handle
241 {
242   /**
243    * Configuration to use.
244    */
245   const struct GNUNET_CONFIGURATION_Handle *cfg;
246
247   /**
248    * Socket (if available).
249    */
250   struct GNUNET_CLIENT_Connection *client;
251
252   /**
253    * Closure for 'cb'.
254    */
255   void *cb_cls;
256
257   /**
258    * Head of active operations.
259    */
260   struct GNUNET_IDENTITY_PROVIDER_Operation *op_head;
261
262   /**
263    * Tail of active operations.
264    */
265   struct GNUNET_IDENTITY_PROVIDER_Operation *op_tail;
266
267   /**
268    * Head of active iterations
269    */
270   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it_head;
271
272   /**
273    * Tail of active iterations
274    */
275   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it_tail;
276
277   /**
278    * Head of active iterations
279    */
280   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it_head;
281
282   /**
283    * Tail of active iterations
284    */
285   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it_tail;
286
287
288   /**
289    * Currently pending transmission request, or NULL for none.
290    */
291   struct GNUNET_CLIENT_TransmitHandle *th;
292
293   /**
294    * Task doing exponential back-off trying to reconnect.
295    */
296   struct GNUNET_SCHEDULER_Task * reconnect_task;
297
298   /**
299    * Time for next connect retry.
300    */
301   struct GNUNET_TIME_Relative reconnect_backoff;
302
303   /**
304    * Connection to service (if available).
305    */
306   struct GNUNET_MQ_Handle *mq;
307
308   /**
309    * Request Id generator.  Incremented by one for each request.
310    */
311   uint32_t r_id_gen;
312
313   /**
314    * Are we polling for incoming messages right now?
315    */
316   int in_receive;
317
318 };
319
320 /**
321  * Try again to connect to the service.
322  *
323  * @param h handle to the identity provider service.
324  */
325 static void
326 reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h);
327
328 /**
329  * Reconnect
330  *
331  * @param cls the handle
332  */
333 static void
334 reconnect_task (void *cls)
335 {
336   struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls;
337
338   handle->reconnect_task = NULL;
339   reconnect (handle);
340 }
341
342
343 /**
344  * Disconnect from service and then reconnect.
345  *
346  * @param handle our service
347  */
348 static void
349 force_reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *handle)
350 {
351   GNUNET_MQ_destroy (handle->mq);
352   handle->mq = NULL;
353   handle->reconnect_backoff
354     = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
355   handle->reconnect_task
356     = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
357                                     &reconnect_task,
358                                     handle);
359 }
360
361 /**
362  * Free @a it.
363  *
364  * @param it entry to free
365  */
366 static void
367 free_it (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it)
368 {
369   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
370
371   GNUNET_CONTAINER_DLL_remove (h->it_head,
372                                h->it_tail,
373                                it);
374   if (NULL != it->env)
375     GNUNET_MQ_discard (it->env);
376   GNUNET_free (it);
377 }
378
379 static void
380 free_op (struct GNUNET_IDENTITY_PROVIDER_Operation* op)
381 {
382   if (NULL == op)
383     return;
384   if (NULL != op->env)
385     GNUNET_MQ_discard (op->env);
386   GNUNET_free(op);
387 }
388
389
390 /**
391  * Generic error handler, called with the appropriate error code and
392  * the same closure specified at the creation of the message queue.
393  * Not every message queue implementation supports an error handler.
394  *
395  * @param cls closure with the `struct GNUNET_GNS_Handle *`
396  * @param error error code
397  */
398 static void
399 mq_error_handler (void *cls,
400                   enum GNUNET_MQ_Error error)
401 {
402   struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls;
403   force_reconnect (handle);
404 }
405
406 /**
407  * Handle an incoming message of type
408  * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE
409  *
410  * @param cls
411  * @param msg the message we received
412  */
413 static void
414 handle_attribute_store_response (void *cls,
415                               const struct AttributeStoreResultMessage *msg)
416 {
417   struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls;
418   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
419   uint32_t r_id = ntohl (msg->id);
420   int res;
421   const char *emsg;
422
423   for (op = h->op_head; NULL != op; op = op->next)
424     if (op->r_id == r_id)
425       break;
426   if (NULL == op)
427     return;
428
429   res = ntohl (msg->op_result);
430   LOG (GNUNET_ERROR_TYPE_DEBUG,
431        "Received ATTRIBUTE_STORE_RESPONSE with result %d\n",
432        res);
433
434   /* TODO: add actual error message to response... */
435   if (GNUNET_SYSERR == res)
436     emsg = _("failed to store record\n");
437   else
438     emsg = NULL;
439   if (NULL != op->as_cb)
440     op->as_cb (op->cls,
441               res,
442               emsg);
443   GNUNET_CONTAINER_DLL_remove (h->op_head,
444                                h->op_tail,
445                                op);
446   free_op (op);
447
448 }
449
450
451 /**
452  * Handle an incoming message of type
453  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT
454  *
455  * @param cls
456  * @param msg the message we received
457  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
458  */
459 static int
460 check_consume_ticket_result (void *cls,
461                              const struct ConsumeTicketResultMessage *msg)
462 {
463   size_t msg_len;
464   size_t attrs_len;
465
466   msg_len = ntohs (msg->header.size);
467   attrs_len = ntohs (msg->attrs_len);
468   if (msg_len != sizeof (struct ConsumeTicketResultMessage) + attrs_len)
469   {
470     GNUNET_break (0);
471     return GNUNET_SYSERR;
472   }
473   return GNUNET_OK;
474 }
475
476
477 /**
478  * Handle an incoming message of type
479  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT
480  *
481  * @param cls
482  * @param msg the message we received
483  */
484 static void
485 handle_consume_ticket_result (void *cls,
486                               const struct ConsumeTicketResultMessage *msg)
487 {
488   struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls;
489   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
490   size_t attrs_len;
491   uint32_t r_id = ntohl (msg->id);
492
493   attrs_len = ntohs (msg->attrs_len);
494   LOG (GNUNET_ERROR_TYPE_DEBUG,
495        "Processing attribute result.\n");
496
497
498   for (op = h->op_head; NULL != op; op = op->next)
499     if (op->r_id == r_id)
500       break;
501   if (NULL == op)
502     return;
503
504   {
505     struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs;
506     struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
507     attrs = GNUNET_IDENTITY_ATTRIBUTE_list_deserialize ((char*)&msg[1],
508                                         attrs_len);
509     if (NULL != op->ar_cb)
510     {
511       if (NULL == attrs)
512       {
513         op->ar_cb (op->cls,
514                    &msg->identity,
515                    NULL);
516       }
517       else
518       {
519         for (le = attrs->list_head; NULL != le; le = le->next)
520           op->ar_cb (op->cls,
521                      &msg->identity,
522                      le->claim);
523         GNUNET_IDENTITY_ATTRIBUTE_list_destroy (attrs);
524       }
525     }
526     if (NULL != op)
527     {
528       op->ar_cb (op->cls,
529                  NULL,
530                  NULL);
531       GNUNET_CONTAINER_DLL_remove (h->op_head,
532                                    h->op_tail,
533                                    op);
534       free_op (op);
535     }
536     return;
537   }
538   GNUNET_assert (0);
539 }
540
541
542 /**
543  * Handle an incoming message of type
544  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT
545  *
546  * @param cls
547  * @param msg the message we received
548  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
549  */
550 static int
551 check_attribute_result (void *cls,
552                         const struct AttributeResultMessage *msg)
553 {
554   size_t msg_len;
555   size_t attr_len;
556
557   msg_len = ntohs (msg->header.size);
558   attr_len = ntohs (msg->attr_len);
559   if (msg_len != sizeof (struct AttributeResultMessage) + attr_len)
560   {
561     GNUNET_break (0);
562     return GNUNET_SYSERR;
563   }
564   return GNUNET_OK;
565 }
566
567
568 /**
569  * Handle an incoming message of type
570  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT
571  *
572  * @param cls
573  * @param msg the message we received
574  */
575 static void
576 handle_attribute_result (void *cls,
577                          const struct AttributeResultMessage *msg)
578 {
579   static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy;
580   struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls;
581   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it;
582   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
583   size_t attr_len;
584   uint32_t r_id = ntohl (msg->id);
585
586   attr_len = ntohs (msg->attr_len);
587   LOG (GNUNET_ERROR_TYPE_DEBUG,
588        "Processing attribute result.\n");
589
590
591   for (it = h->it_head; NULL != it; it = it->next)
592     if (it->r_id == r_id)
593       break;
594   for (op = h->op_head; NULL != op; op = op->next)
595     if (op->r_id == r_id)
596       break;
597   if ((NULL == it) && (NULL == op))
598     return;
599
600   if ( (0 == (memcmp (&msg->identity,
601                       &identity_dummy,
602                       sizeof (identity_dummy)))) )
603   {
604     if ((NULL == it) && (NULL == op))
605     {
606       GNUNET_break (0);
607       force_reconnect (h);
608       return;
609     }
610     if (NULL != it)
611     {
612       if (NULL != it->finish_cb)
613         it->finish_cb (it->finish_cb_cls);
614       free_it (it);
615     }
616     if (NULL != op)
617     {
618       if (NULL != op->ar_cb)
619         op->ar_cb (op->cls,
620                    NULL,
621                    NULL);
622       GNUNET_CONTAINER_DLL_remove (h->op_head,
623                                    h->op_tail,
624                                    op);
625       free_op (op);
626
627     }
628     return;
629   }
630
631   {
632     struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr;
633     attr = GNUNET_IDENTITY_ATTRIBUTE_deserialize ((char*)&msg[1],
634                                                   attr_len);
635     if (NULL != it)
636     {
637       if (NULL != it->proc)
638         it->proc (it->proc_cls,
639                   &msg->identity,
640                   attr);
641     } else if (NULL != op)
642     {
643       if (NULL != op->ar_cb)
644         op->ar_cb (op->cls,
645                    &msg->identity,
646                    attr);
647
648     }
649     GNUNET_free (attr);
650     return;
651   }
652   GNUNET_assert (0);
653 }
654
655 /**
656  * Handle an incoming message of type
657  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT
658  *
659  * @param cls
660  * @param msg the message we received
661  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
662  */
663 static int
664 check_ticket_result (void *cls,
665                      const struct TicketResultMessage *msg)
666 {
667   size_t msg_len;
668
669   msg_len = ntohs (msg->header.size);
670   if (msg_len < sizeof (struct TicketResultMessage))
671   {
672     GNUNET_break (0);
673     return GNUNET_SYSERR;
674   }
675   return GNUNET_OK;
676 }
677
678
679
680 /**
681  * Handle an incoming message of type
682  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT
683  *
684  * @param cls
685  * @param msg the message we received
686  */
687 static void
688 handle_ticket_result (void *cls,
689                       const struct TicketResultMessage *msg)
690 {
691   struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls;
692   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
693   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it;
694   const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket;
695   uint32_t r_id = ntohl (msg->id);
696   size_t msg_len;
697
698   for (op = handle->op_head; NULL != op; op = op->next)
699     if (op->r_id == r_id)
700       break;
701   for (it = handle->ticket_it_head; NULL != it; it = it->next)
702     if (it->r_id == r_id)
703       break;
704   if ((NULL == op) && (NULL == it))
705     return;
706   msg_len = ntohs (msg->header.size);
707   if (NULL != op)
708   {
709     GNUNET_CONTAINER_DLL_remove (handle->op_head,
710                                  handle->op_tail,
711                                  op);
712     if (msg_len == sizeof (struct TicketResultMessage))
713     {
714       if (NULL != op->tr_cb)
715         op->tr_cb (op->cls, NULL);
716     } else {
717       ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket *)&msg[1];
718       if (NULL != op->tr_cb)
719         op->tr_cb (op->cls, ticket);
720     }
721     free_op (op);
722     return;
723   } else if (NULL != it) {
724     if (msg_len == sizeof (struct TicketResultMessage))
725     {
726       if (NULL != it->tr_cb)
727         GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head,
728                                      handle->ticket_it_tail,
729                                      it);
730       it->finish_cb (it->finish_cb_cls);
731       GNUNET_free (it);
732     } else {
733       ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket *)&msg[1];
734       if (NULL != it->tr_cb)
735         it->tr_cb (it->cls, ticket);
736     }
737     return;
738   }
739   GNUNET_break (0);
740 }
741
742
743 /**
744  * Handle an incoming message of type
745  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT
746  *
747  * @param cls
748  * @param msg the message we received
749  */
750 static void
751 handle_revoke_ticket_result (void *cls,
752                              const struct RevokeTicketResultMessage *msg)
753 {
754   struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls;
755   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
756   uint32_t r_id = ntohl (msg->id);
757   int32_t success;
758
759   LOG (GNUNET_ERROR_TYPE_DEBUG,
760        "Processing revocation result.\n");
761
762
763   for (op = h->op_head; NULL != op; op = op->next)
764     if (op->r_id == r_id)
765       break;
766   if (NULL == op)
767     return;
768   success = ntohl (msg->success);
769   {
770     if (NULL != op->rvk_cb)
771     {
772       op->rvk_cb (op->cls,
773                   success,
774                   NULL);
775     }
776     GNUNET_CONTAINER_DLL_remove (h->op_head,
777                                  h->op_tail,
778                                  op);
779     free_op (op);
780     return;
781   }
782   GNUNET_assert (0);
783 }
784
785
786
787 /**
788  * Try again to connect to the service.
789  *
790  * @param h handle to the identity provider service.
791  */
792 static void
793 reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h)
794 {
795   struct GNUNET_MQ_MessageHandler handlers[] = {
796     GNUNET_MQ_hd_fixed_size (attribute_store_response,
797                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE_RESPONSE,
798                              struct AttributeStoreResultMessage,
799                              h),
800     GNUNET_MQ_hd_var_size (attribute_result,
801                            GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT,
802                            struct AttributeResultMessage,
803                            h),
804     GNUNET_MQ_hd_var_size (ticket_result,
805                            GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT,
806                            struct TicketResultMessage,
807                            h),
808     GNUNET_MQ_hd_var_size (consume_ticket_result,
809                            GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT,
810                            struct ConsumeTicketResultMessage,
811                            h),
812     GNUNET_MQ_hd_fixed_size (revoke_ticket_result,
813                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT,
814                              struct RevokeTicketResultMessage,
815                              h),
816     GNUNET_MQ_handler_end ()
817   };
818   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
819
820   GNUNET_assert (NULL == h->mq);
821   LOG (GNUNET_ERROR_TYPE_DEBUG,
822        "Connecting to identity provider service.\n");
823
824   h->mq = GNUNET_CLIENT_connect (h->cfg,
825                                  "identity-provider",
826                                  handlers,
827                                  &mq_error_handler,
828                                  h);
829   if (NULL == h->mq)
830     return;
831   for (op = h->op_head; NULL != op; op = op->next)
832     GNUNET_MQ_send_copy (h->mq,
833                          op->env);
834 }
835
836
837 /**
838  * Connect to the identity provider service.
839  *
840  * @param cfg the configuration to use
841  * @return handle to use
842  */
843 struct GNUNET_IDENTITY_PROVIDER_Handle *
844 GNUNET_IDENTITY_PROVIDER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
845 {
846   struct GNUNET_IDENTITY_PROVIDER_Handle *h;
847
848   h = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Handle);
849   h->cfg = cfg;
850   reconnect (h);
851   if (NULL == h->mq)
852   {
853     GNUNET_free (h);
854     return NULL;
855   }
856   return h;
857 }
858
859
860 /**
861  * Cancel an operation. Note that the operation MAY still
862  * be executed; this merely cancels the continuation; if the request
863  * was already transmitted, the service may still choose to complete
864  * the operation.
865  *
866  * @param op operation to cancel
867  */
868 void
869 GNUNET_IDENTITY_PROVIDER_cancel (struct GNUNET_IDENTITY_PROVIDER_Operation *op)
870 {
871   struct GNUNET_IDENTITY_PROVIDER_Handle *h = op->h;
872
873   GNUNET_CONTAINER_DLL_remove (h->op_head,
874                                h->op_tail,
875                                op);
876   free_op (op);
877 }
878
879
880 /**
881  * Disconnect from service
882  *
883  * @param h handle to destroy
884  */
885 void
886 GNUNET_IDENTITY_PROVIDER_disconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h)
887 {
888   GNUNET_assert (NULL != h);
889   if (NULL != h->mq)
890   {
891     GNUNET_MQ_destroy (h->mq);
892     h->mq = NULL;
893   }
894   if (NULL != h->reconnect_task)
895   {
896     GNUNET_SCHEDULER_cancel (h->reconnect_task);
897     h->reconnect_task = NULL;
898   }
899   GNUNET_assert (NULL == h->op_head);
900   GNUNET_free (h);
901 }
902
903 /**
904  * Store an attribute.  If the attribute is already present,
905  * it is replaced with the new attribute.
906  *
907  * @param h handle to the identity provider
908  * @param pkey private key of the identity
909  * @param attr the attribute value
910  * @param exp_interval the relative expiration interval for the attribute
911  * @param cont continuation to call when done
912  * @param cont_cls closure for @a cont
913  * @return handle to abort the request
914  */
915 struct GNUNET_IDENTITY_PROVIDER_Operation *
916 GNUNET_IDENTITY_PROVIDER_attribute_store (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
917                                           const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
918                                           const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr,
919                                           const struct GNUNET_TIME_Relative *exp_interval,
920                                           GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cont,
921                                           void *cont_cls)
922 {
923   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
924   struct AttributeStoreMessage *sam;
925   size_t attr_len;
926
927   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
928   op->h = h;
929   op->as_cb = cont;
930   op->cls = cont_cls;
931   op->r_id = h->r_id_gen++;
932   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
933                                     h->op_tail,
934                                     op);
935   attr_len = GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (attr);
936   op->env = GNUNET_MQ_msg_extra (sam,
937                                  attr_len,
938                                  GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE);
939   sam->identity = *pkey;
940   sam->id = htonl (op->r_id);
941   sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
942
943   GNUNET_IDENTITY_ATTRIBUTE_serialize (attr,
944                                        (char*)&sam[1]);
945
946   sam->attr_len = htons (attr_len);
947   if (NULL != h->mq)
948     GNUNET_MQ_send_copy (h->mq,
949                          op->env);
950   return op;
951
952 }
953
954
955 /**
956  * List all attributes for a local identity.
957  * This MUST lock the `struct GNUNET_IDENTITY_PROVIDER_Handle`
958  * for any other calls than #GNUNET_IDENTITY_PROVIDER_get_attributes_next() and
959  * #GNUNET_IDENTITY_PROVIDER_get_attributes_stop. @a proc will be called once
960  * immediately, and then again after
961  * #GNUNET_IDENTITY_PROVIDER_get_attributes_next() is invoked.
962  *
963  * On error (disconnect), @a error_cb will be invoked.
964  * On normal completion, @a finish_cb proc will be
965  * invoked.
966  *
967  * @param h handle to the idp
968  * @param identity identity to access
969  * @param error_cb function to call on error (i.e. disconnect),
970  *        the handle is afterwards invalid
971  * @param error_cb_cls closure for @a error_cb
972  * @param proc function to call on each attribute; it
973  *        will be called repeatedly with a value (if available)
974  * @param proc_cls closure for @a proc
975  * @param finish_cb function to call on completion
976  *        the handle is afterwards invalid
977  * @param finish_cb_cls closure for @a finish_cb
978  * @return an iterator handle to use for iteration
979  */
980 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *
981 GNUNET_IDENTITY_PROVIDER_get_attributes_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
982                                                const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
983                                                GNUNET_SCHEDULER_TaskCallback error_cb,
984                                                void *error_cb_cls,
985                                                GNUNET_IDENTITY_PROVIDER_AttributeResult proc,
986                                                void *proc_cls,
987                                                GNUNET_SCHEDULER_TaskCallback finish_cb,
988                                                void *finish_cb_cls)
989 {
990   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it;
991   struct GNUNET_MQ_Envelope *env;
992   struct AttributeIterationStartMessage *msg;
993   uint32_t rid;
994
995   rid = h->r_id_gen++;
996   it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator);
997   it->h = h;
998   it->error_cb = error_cb;
999   it->error_cb_cls = error_cb_cls;
1000   it->finish_cb = finish_cb;
1001   it->finish_cb_cls = finish_cb_cls;
1002   it->proc = proc;
1003   it->proc_cls = proc_cls;
1004   it->r_id = rid;
1005   it->identity = *identity;
1006   GNUNET_CONTAINER_DLL_insert_tail (h->it_head,
1007                                     h->it_tail,
1008                                     it);
1009   env = GNUNET_MQ_msg (msg,
1010                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_START);
1011   msg->id = htonl (rid);
1012   msg->identity = *identity;
1013   if (NULL == h->mq)
1014     it->env = env;
1015   else
1016     GNUNET_MQ_send (h->mq,
1017                     env);
1018   return it;
1019 }
1020
1021
1022 /**
1023  * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_get_attributes_start
1024  * for the next record.
1025  *
1026  * @param it the iterator
1027  */
1028 void
1029 GNUNET_IDENTITY_PROVIDER_get_attributes_next (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it)
1030 {
1031   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1032   struct AttributeIterationNextMessage *msg;
1033   struct GNUNET_MQ_Envelope *env;
1034
1035   env = GNUNET_MQ_msg (msg,
1036                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_NEXT);
1037   msg->id = htonl (it->r_id);
1038   GNUNET_MQ_send (h->mq,
1039                   env);
1040 }
1041
1042
1043 /**
1044  * Stops iteration and releases the idp handle for further calls.  Must
1045  * be called on any iteration that has not yet completed prior to calling
1046  * #GNUNET_IDENTITY_PROVIDER_disconnect.
1047  *
1048  * @param it the iterator
1049  */
1050 void
1051 GNUNET_IDENTITY_PROVIDER_get_attributes_stop (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it)
1052 {
1053   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1054   struct GNUNET_MQ_Envelope *env;
1055   struct AttributeIterationStopMessage *msg;
1056
1057   if (NULL != h->mq)
1058   {
1059     env = GNUNET_MQ_msg (msg,
1060                          GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_STOP);
1061     msg->id = htonl (it->r_id);
1062     GNUNET_MQ_send (h->mq,
1063                     env);
1064   }
1065   free_it (it);
1066 }
1067
1068
1069 /** TODO
1070  * Issues a ticket to another identity. The identity may use
1071  * @GNUNET_IDENTITY_PROVIDER_authorization_ticket_consume to consume the ticket
1072  * and retrieve the attributes specified in the AttributeList.
1073  *
1074  * @param h the identity provider to use
1075  * @param iss the issuing identity
1076  * @param rp the subject of the ticket (the relying party)
1077  * @param attrs the attributes that the relying party is given access to
1078  * @param cb the callback
1079  * @param cb_cls the callback closure
1080  * @return handle to abort the operation
1081  */
1082 struct GNUNET_IDENTITY_PROVIDER_Operation *
1083 GNUNET_IDENTITY_PROVIDER_ticket_issue (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1084                                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss,
1085                                        const struct GNUNET_CRYPTO_EcdsaPublicKey *rp,
1086                                        const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs,
1087                                        GNUNET_IDENTITY_PROVIDER_TicketCallback cb,
1088                                        void *cb_cls)
1089 {
1090   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
1091   struct IssueTicketMessage *tim;
1092   size_t attr_len;
1093
1094   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
1095   op->h = h;
1096   op->tr_cb = cb;
1097   op->cls = cb_cls;
1098   op->r_id = h->r_id_gen++;
1099   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1100                                     h->op_tail,
1101                                     op);
1102   attr_len = GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (attrs);
1103   op->env = GNUNET_MQ_msg_extra (tim,
1104                                  attr_len,
1105                                  GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_TICKET);
1106   tim->identity = *iss;
1107   tim->rp = *rp;
1108   tim->id = htonl (op->r_id);
1109
1110   GNUNET_IDENTITY_ATTRIBUTE_list_serialize (attrs,
1111                                             (char*)&tim[1]);
1112
1113   tim->attr_len = htons (attr_len);
1114   if (NULL != h->mq)
1115     GNUNET_MQ_send_copy (h->mq,
1116                          op->env);
1117   return op;
1118 }
1119
1120 /**
1121  * Consumes an issued ticket. The ticket is persisted
1122  * and used to retrieve identity information from the issuer
1123  *
1124  * @param h the identity provider to use
1125  * @param identity the identity that is the subject of the issued ticket (the relying party)
1126  * @param ticket the issued ticket to consume
1127  * @param cb the callback to call
1128  * @param cb_cls the callback closure
1129  * @return handle to abort the operation
1130  */
1131 struct GNUNET_IDENTITY_PROVIDER_Operation *
1132 GNUNET_IDENTITY_PROVIDER_ticket_consume (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1133                                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1134                                          const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
1135                                          GNUNET_IDENTITY_PROVIDER_AttributeResult cb,
1136                                          void *cb_cls)
1137 {
1138   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
1139   struct ConsumeTicketMessage *ctm;
1140
1141   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
1142   op->h = h;
1143   op->ar_cb = cb;
1144   op->cls = cb_cls;
1145   op->r_id = h->r_id_gen++;
1146   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1147                                     h->op_tail,
1148                                     op);
1149   op->env = GNUNET_MQ_msg_extra (ctm,
1150                                  sizeof (const struct GNUNET_IDENTITY_PROVIDER_Ticket),
1151                                  GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET);
1152   ctm->identity = *identity;
1153   ctm->id = htonl (op->r_id);
1154
1155   GNUNET_memcpy ((char*)&ctm[1],
1156                  ticket,
1157                  sizeof (const struct GNUNET_IDENTITY_PROVIDER_Ticket));
1158
1159   if (NULL != h->mq)
1160     GNUNET_MQ_send_copy (h->mq,
1161                          op->env);
1162   return op;
1163
1164 }
1165
1166
1167 /**
1168  * Lists all tickets that have been issued to remote
1169  * identites (relying parties)
1170  *
1171  * @param h the identity provider to use
1172  * @param identity the issuing identity
1173  * @param error_cb function to call on error (i.e. disconnect),
1174  *        the handle is afterwards invalid
1175  * @param error_cb_cls closure for @a error_cb
1176  * @param proc function to call on each ticket; it
1177  *        will be called repeatedly with a value (if available)
1178  * @param proc_cls closure for @a proc
1179  * @param finish_cb function to call on completion
1180  *        the handle is afterwards invalid
1181  * @param finish_cb_cls closure for @a finish_cb
1182  * @return an iterator handle to use for iteration
1183  */
1184 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *
1185 GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1186                                                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1187                                                  GNUNET_SCHEDULER_TaskCallback error_cb,
1188                                                  void *error_cb_cls,
1189                                                  GNUNET_IDENTITY_PROVIDER_TicketCallback proc,
1190                                                  void *proc_cls,
1191                                                  GNUNET_SCHEDULER_TaskCallback finish_cb,
1192                                                  void *finish_cb_cls)
1193 {
1194   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it;
1195   struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
1196   struct GNUNET_MQ_Envelope *env;
1197   struct TicketIterationStartMessage *msg;
1198   uint32_t rid;
1199
1200   GNUNET_CRYPTO_ecdsa_key_get_public (identity,
1201                                       &identity_pub);
1202   rid = h->r_id_gen++;
1203   it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_TicketIterator);
1204   it->h = h;
1205   it->error_cb = error_cb;
1206   it->error_cb_cls = error_cb_cls;
1207   it->finish_cb = finish_cb;
1208   it->finish_cb_cls = finish_cb_cls;
1209   it->tr_cb = proc;
1210   it->cls = proc_cls;
1211   it->r_id = rid;
1212   GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head,
1213                                     h->ticket_it_tail,
1214                                     it);
1215   env = GNUNET_MQ_msg (msg,
1216                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START);
1217   msg->id = htonl (rid);
1218   msg->identity = identity_pub;
1219   msg->is_audience = htonl (GNUNET_NO);
1220   if (NULL == h->mq)
1221     it->env = env;
1222   else
1223     GNUNET_MQ_send (h->mq,
1224                     env);
1225   return it;
1226
1227 }
1228
1229
1230 /**
1231  * Lists all tickets that have been issued to remote
1232  * identites (relying parties)
1233  *
1234  * @param h the identity provider to use
1235  * @param identity the issuing identity
1236  * @param error_cb function to call on error (i.e. disconnect),
1237  *        the handle is afterwards invalid
1238  * @param error_cb_cls closure for @a error_cb
1239  * @param proc function to call on each ticket; it
1240  *        will be called repeatedly with a value (if available)
1241  * @param proc_cls closure for @a proc
1242  * @param finish_cb function to call on completion
1243  *        the handle is afterwards invalid
1244  * @param finish_cb_cls closure for @a finish_cb
1245  * @return an iterator handle to use for iteration
1246  */
1247 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *
1248 GNUNET_IDENTITY_PROVIDER_ticket_iteration_start_rp (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1249                                                     const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1250                                                     GNUNET_SCHEDULER_TaskCallback error_cb,
1251                                                     void *error_cb_cls,
1252                                                     GNUNET_IDENTITY_PROVIDER_TicketCallback proc,
1253                                                     void *proc_cls,
1254                                                     GNUNET_SCHEDULER_TaskCallback finish_cb,
1255                                                     void *finish_cb_cls)
1256 {
1257   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it;
1258   struct GNUNET_MQ_Envelope *env;
1259   struct TicketIterationStartMessage *msg;
1260   uint32_t rid;
1261
1262   rid = h->r_id_gen++;
1263   it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_TicketIterator);
1264   it->h = h;
1265   it->error_cb = error_cb;
1266   it->error_cb_cls = error_cb_cls;
1267   it->finish_cb = finish_cb;
1268   it->finish_cb_cls = finish_cb_cls;
1269   it->tr_cb = proc;
1270   it->cls = proc_cls;
1271   it->r_id = rid;
1272   GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head,
1273                                     h->ticket_it_tail,
1274                                     it);
1275   env = GNUNET_MQ_msg (msg,
1276                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START);
1277   msg->id = htonl (rid);
1278   msg->identity = *identity;
1279   msg->is_audience = htonl (GNUNET_YES);
1280   if (NULL == h->mq)
1281     it->env = env;
1282   else
1283     GNUNET_MQ_send (h->mq,
1284                     env);
1285   return it;
1286
1287
1288 }
1289
1290 /**
1291  * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_ticket_iteration_start
1292  * for the next record.
1293  *
1294  * @param it the iterator
1295  */
1296 void
1297 GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it)
1298 {
1299   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1300   struct TicketIterationNextMessage *msg;
1301   struct GNUNET_MQ_Envelope *env;
1302
1303   env = GNUNET_MQ_msg (msg,
1304                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT);
1305   msg->id = htonl (it->r_id);
1306   GNUNET_MQ_send (h->mq,
1307                   env);
1308 }
1309
1310
1311 /**
1312  * Stops iteration and releases the idp handle for further calls.  Must
1313  * be called on any iteration that has not yet completed prior to calling
1314  * #GNUNET_IDENTITY_PROVIDER_disconnect.
1315  *
1316  * @param it the iterator
1317  */
1318 void
1319 GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it)
1320 {
1321   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1322   struct GNUNET_MQ_Envelope *env;
1323   struct TicketIterationStopMessage *msg;
1324
1325   if (NULL != h->mq)
1326   {
1327     env = GNUNET_MQ_msg (msg,
1328                          GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP);
1329     msg->id = htonl (it->r_id);
1330     GNUNET_MQ_send (h->mq,
1331                     env);
1332   }
1333   GNUNET_free (it);
1334 }
1335
1336 /**
1337  * Revoked an issued ticket. The relying party will be unable to retrieve
1338  * updated attributes.
1339  *
1340  * @param h the identity provider to use
1341  * @param identity the issuing identity
1342  * @param ticket the ticket to revoke
1343  * @param cb the callback
1344  * @param cb_cls the callback closure
1345  * @return handle to abort the operation
1346  */
1347 struct GNUNET_IDENTITY_PROVIDER_Operation *
1348 GNUNET_IDENTITY_PROVIDER_ticket_revoke (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1349                                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1350                                         const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
1351                                         GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cb,
1352                                         void *cb_cls)
1353 {
1354   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
1355   struct GNUNET_MQ_Envelope *env;
1356   struct RevokeTicketMessage *msg;
1357   uint32_t rid;
1358
1359   rid = h->r_id_gen++;
1360   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
1361   op->h = h;
1362   op->rvk_cb = cb;
1363   op->cls = cb_cls;
1364   op->r_id = rid;
1365   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1366                                     h->op_tail,
1367                                     op);
1368   env = GNUNET_MQ_msg_extra (msg,
1369                              sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket),
1370                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET);
1371   msg->id = htonl (rid);
1372   msg->identity = *identity;
1373   GNUNET_memcpy (&msg[1],
1374                  ticket,
1375                  sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket));
1376   if (NULL == h->mq)
1377     op->env = env;
1378   else
1379     GNUNET_MQ_send (h->mq,
1380                     env);
1381   return op;
1382 }
1383
1384
1385
1386 /* end of identity_provider_api.c */