add attribute expiration
[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   GNUNET_MQ_discard (op->env);
877   free_op (op);
878 }
879
880
881 /**
882  * Disconnect from service
883  *
884  * @param h handle to destroy
885  */
886 void
887 GNUNET_IDENTITY_PROVIDER_disconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h)
888 {
889   GNUNET_assert (NULL != h);
890   if (NULL != h->mq)
891   {
892     GNUNET_MQ_destroy (h->mq);
893     h->mq = NULL;
894   }
895   if (NULL != h->reconnect_task)
896   {
897     GNUNET_SCHEDULER_cancel (h->reconnect_task);
898     h->reconnect_task = NULL;
899   }
900   GNUNET_assert (NULL == h->op_head);
901   GNUNET_free (h);
902 }
903
904 /**
905  * Store an attribute.  If the attribute is already present,
906  * it is replaced with the new attribute.
907  *
908  * @param h handle to the identity provider
909  * @param pkey private key of the identity
910  * @param attr the attribute value
911  * @param exp_interval the relative expiration interval for the attribute
912  * @param cont continuation to call when done
913  * @param cont_cls closure for @a cont
914  * @return handle to abort the request
915  */
916 struct GNUNET_IDENTITY_PROVIDER_Operation *
917 GNUNET_IDENTITY_PROVIDER_attribute_store (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
918                                           const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
919                                           const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr,
920                                           const struct GNUNET_TIME_Relative *exp_interval,
921                                           GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cont,
922                                           void *cont_cls)
923 {
924   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
925   struct AttributeStoreMessage *sam;
926   size_t attr_len;
927
928   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
929   op->h = h;
930   op->as_cb = cont;
931   op->cls = cont_cls;
932   op->r_id = h->r_id_gen++;
933   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
934                                     h->op_tail,
935                                     op);
936   attr_len = GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (attr);
937   op->env = GNUNET_MQ_msg_extra (sam,
938                                  attr_len,
939                                  GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE);
940   sam->identity = *pkey;
941   sam->id = htonl (op->r_id);
942   sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
943
944   GNUNET_IDENTITY_ATTRIBUTE_serialize (attr,
945                                        (char*)&sam[1]);
946
947   sam->attr_len = htons (attr_len);
948   if (NULL != h->mq)
949     GNUNET_MQ_send_copy (h->mq,
950                          op->env);
951   return op;
952
953 }
954
955
956 /**
957  * List all attributes for a local identity. 
958  * This MUST lock the `struct GNUNET_IDENTITY_PROVIDER_Handle`
959  * for any other calls than #GNUNET_IDENTITY_PROVIDER_get_attributes_next() and
960  * #GNUNET_IDENTITY_PROVIDER_get_attributes_stop. @a proc will be called once
961  * immediately, and then again after
962  * #GNUNET_IDENTITY_PROVIDER_get_attributes_next() is invoked.
963  *
964  * On error (disconnect), @a error_cb will be invoked.
965  * On normal completion, @a finish_cb proc will be
966  * invoked.
967  *
968  * @param h handle to the idp
969  * @param identity identity to access
970  * @param error_cb function to call on error (i.e. disconnect),
971  *        the handle is afterwards invalid
972  * @param error_cb_cls closure for @a error_cb
973  * @param proc function to call on each attribute; it
974  *        will be called repeatedly with a value (if available)
975  * @param proc_cls closure for @a proc
976  * @param finish_cb function to call on completion
977  *        the handle is afterwards invalid
978  * @param finish_cb_cls closure for @a finish_cb
979  * @return an iterator handle to use for iteration
980  */
981 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *
982 GNUNET_IDENTITY_PROVIDER_get_attributes_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
983                                                const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
984                                                GNUNET_SCHEDULER_TaskCallback error_cb,
985                                                void *error_cb_cls,
986                                                GNUNET_IDENTITY_PROVIDER_AttributeResult proc,
987                                                void *proc_cls,
988                                                GNUNET_SCHEDULER_TaskCallback finish_cb,
989                                                void *finish_cb_cls)
990 {
991   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it;
992   struct GNUNET_MQ_Envelope *env;
993   struct AttributeIterationStartMessage *msg;
994   uint32_t rid;
995
996   rid = h->r_id_gen++;
997   it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator);
998   it->h = h;
999   it->error_cb = error_cb;
1000   it->error_cb_cls = error_cb_cls;
1001   it->finish_cb = finish_cb;
1002   it->finish_cb_cls = finish_cb_cls;
1003   it->proc = proc;
1004   it->proc_cls = proc_cls;
1005   it->r_id = rid;
1006   it->identity = *identity;
1007   GNUNET_CONTAINER_DLL_insert_tail (h->it_head,
1008                                     h->it_tail,
1009                                     it);
1010   env = GNUNET_MQ_msg (msg,
1011                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_START);
1012   msg->id = htonl (rid);
1013   msg->identity = *identity;
1014   if (NULL == h->mq)
1015     it->env = env;
1016   else
1017     GNUNET_MQ_send (h->mq,
1018                     env);
1019   return it;
1020 }
1021
1022
1023 /**
1024  * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_get_attributes_start
1025  * for the next record.
1026  *
1027  * @param it the iterator
1028  */
1029 void
1030 GNUNET_IDENTITY_PROVIDER_get_attributes_next (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it)
1031 {
1032   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1033   struct AttributeIterationNextMessage *msg;
1034   struct GNUNET_MQ_Envelope *env;
1035
1036   env = GNUNET_MQ_msg (msg,
1037                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_NEXT);
1038   msg->id = htonl (it->r_id);
1039   GNUNET_MQ_send (h->mq,
1040                   env);
1041 }
1042
1043
1044 /**
1045  * Stops iteration and releases the idp handle for further calls.  Must
1046  * be called on any iteration that has not yet completed prior to calling
1047  * #GNUNET_IDENTITY_PROVIDER_disconnect.
1048  *
1049  * @param it the iterator
1050  */
1051 void
1052 GNUNET_IDENTITY_PROVIDER_get_attributes_stop (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it)
1053 {
1054   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1055   struct GNUNET_MQ_Envelope *env;
1056   struct AttributeIterationStopMessage *msg;
1057
1058   if (NULL != h->mq)
1059   {
1060     env = GNUNET_MQ_msg (msg,
1061                          GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_STOP);
1062     msg->id = htonl (it->r_id);
1063     GNUNET_MQ_send (h->mq,
1064                     env);
1065   }
1066   free_it (it);
1067 }
1068
1069
1070 /** TODO
1071  * Issues a ticket to another identity. The identity may use
1072  * @GNUNET_IDENTITY_PROVIDER_authorization_ticket_consume to consume the ticket
1073  * and retrieve the attributes specified in the AttributeList.
1074  *
1075  * @param h the identity provider to use
1076  * @param iss the issuing identity
1077  * @param rp the subject of the ticket (the relying party)
1078  * @param attrs the attributes that the relying party is given access to
1079  * @param cb the callback
1080  * @param cb_cls the callback closure
1081  * @return handle to abort the operation
1082  */
1083 struct GNUNET_IDENTITY_PROVIDER_Operation *
1084 GNUNET_IDENTITY_PROVIDER_ticket_issue (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1085                                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss,
1086                                        const struct GNUNET_CRYPTO_EcdsaPublicKey *rp,
1087                                        const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs,
1088                                        GNUNET_IDENTITY_PROVIDER_TicketCallback cb,
1089                                        void *cb_cls)
1090 {
1091   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
1092   struct IssueTicketMessage *tim;
1093   size_t attr_len;
1094
1095   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
1096   op->h = h;
1097   op->tr_cb = cb;
1098   op->cls = cb_cls;
1099   op->r_id = h->r_id_gen++;
1100   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1101                                     h->op_tail,
1102                                     op);
1103   attr_len = GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (attrs);
1104   op->env = GNUNET_MQ_msg_extra (tim,
1105                                  attr_len,
1106                                  GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_TICKET);
1107   tim->identity = *iss;
1108   tim->rp = *rp;
1109   tim->id = htonl (op->r_id);
1110
1111   GNUNET_IDENTITY_ATTRIBUTE_list_serialize (attrs,
1112                                             (char*)&tim[1]);
1113
1114   tim->attr_len = htons (attr_len);
1115   if (NULL != h->mq)
1116     GNUNET_MQ_send_copy (h->mq,
1117                          op->env);
1118   return op;
1119 }
1120
1121 /**
1122  * Consumes an issued ticket. The ticket is persisted
1123  * and used to retrieve identity information from the issuer
1124  *
1125  * @param h the identity provider to use
1126  * @param identity the identity that is the subject of the issued ticket (the relying party)
1127  * @param ticket the issued ticket to consume
1128  * @param cb the callback to call
1129  * @param cb_cls the callback closure
1130  * @return handle to abort the operation
1131  */
1132 struct GNUNET_IDENTITY_PROVIDER_Operation *
1133 GNUNET_IDENTITY_PROVIDER_ticket_consume (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1134                                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1135                                          const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
1136                                          GNUNET_IDENTITY_PROVIDER_AttributeResult cb,
1137                                          void *cb_cls)
1138 {
1139   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
1140   struct ConsumeTicketMessage *ctm;
1141
1142   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
1143   op->h = h;
1144   op->ar_cb = cb;
1145   op->cls = cb_cls;
1146   op->r_id = h->r_id_gen++;
1147   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1148                                     h->op_tail,
1149                                     op);
1150   op->env = GNUNET_MQ_msg_extra (ctm,
1151                                  sizeof (const struct GNUNET_IDENTITY_PROVIDER_Ticket),
1152                                  GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET);
1153   ctm->identity = *identity;
1154   ctm->id = htonl (op->r_id);
1155
1156   GNUNET_memcpy ((char*)&ctm[1],
1157                  ticket,
1158                  sizeof (const struct GNUNET_IDENTITY_PROVIDER_Ticket));
1159
1160   if (NULL != h->mq)
1161     GNUNET_MQ_send_copy (h->mq,
1162                          op->env);
1163   return op;
1164
1165 }
1166
1167
1168 /**
1169  * Lists all tickets that have been issued to remote
1170  * identites (relying parties)
1171  *
1172  * @param h the identity provider to use
1173  * @param identity the issuing identity
1174  * @param error_cb function to call on error (i.e. disconnect),
1175  *        the handle is afterwards invalid
1176  * @param error_cb_cls closure for @a error_cb
1177  * @param proc function to call on each ticket; it
1178  *        will be called repeatedly with a value (if available)
1179  * @param proc_cls closure for @a proc
1180  * @param finish_cb function to call on completion
1181  *        the handle is afterwards invalid
1182  * @param finish_cb_cls closure for @a finish_cb
1183  * @return an iterator handle to use for iteration
1184  */
1185 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *
1186 GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1187                                                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1188                                                  GNUNET_SCHEDULER_TaskCallback error_cb,
1189                                                  void *error_cb_cls,
1190                                                  GNUNET_IDENTITY_PROVIDER_TicketCallback proc,
1191                                                  void *proc_cls,
1192                                                  GNUNET_SCHEDULER_TaskCallback finish_cb,
1193                                                  void *finish_cb_cls)
1194 {
1195   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it;
1196   struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
1197   struct GNUNET_MQ_Envelope *env;
1198   struct TicketIterationStartMessage *msg;
1199   uint32_t rid;
1200
1201   GNUNET_CRYPTO_ecdsa_key_get_public (identity,
1202                                       &identity_pub);
1203   rid = h->r_id_gen++;
1204   it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_TicketIterator);
1205   it->h = h;
1206   it->error_cb = error_cb;
1207   it->error_cb_cls = error_cb_cls;
1208   it->finish_cb = finish_cb;
1209   it->finish_cb_cls = finish_cb_cls;
1210   it->tr_cb = proc;
1211   it->cls = proc_cls;
1212   it->r_id = rid;
1213   GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head,
1214                                     h->ticket_it_tail,
1215                                     it);
1216   env = GNUNET_MQ_msg (msg,
1217                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START);
1218   msg->id = htonl (rid);
1219   msg->identity = identity_pub;
1220   msg->is_audience = htonl (GNUNET_NO);
1221   if (NULL == h->mq)
1222     it->env = env;
1223   else
1224     GNUNET_MQ_send (h->mq,
1225                     env);
1226   return it;
1227
1228 }
1229
1230
1231 /**
1232  * Lists all tickets that have been issued to remote
1233  * identites (relying parties)
1234  *
1235  * @param h the identity provider to use
1236  * @param identity the issuing identity
1237  * @param error_cb function to call on error (i.e. disconnect),
1238  *        the handle is afterwards invalid
1239  * @param error_cb_cls closure for @a error_cb
1240  * @param proc function to call on each ticket; it
1241  *        will be called repeatedly with a value (if available)
1242  * @param proc_cls closure for @a proc
1243  * @param finish_cb function to call on completion
1244  *        the handle is afterwards invalid
1245  * @param finish_cb_cls closure for @a finish_cb
1246  * @return an iterator handle to use for iteration
1247  */
1248 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *
1249 GNUNET_IDENTITY_PROVIDER_ticket_iteration_start_rp (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1250                                                     const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1251                                                     GNUNET_SCHEDULER_TaskCallback error_cb,
1252                                                     void *error_cb_cls,
1253                                                     GNUNET_IDENTITY_PROVIDER_TicketCallback proc,
1254                                                     void *proc_cls,
1255                                                     GNUNET_SCHEDULER_TaskCallback finish_cb,
1256                                                     void *finish_cb_cls)
1257 {
1258   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it;
1259   struct GNUNET_MQ_Envelope *env;
1260   struct TicketIterationStartMessage *msg;
1261   uint32_t rid;
1262
1263   rid = h->r_id_gen++;
1264   it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_TicketIterator);
1265   it->h = h;
1266   it->error_cb = error_cb;
1267   it->error_cb_cls = error_cb_cls;
1268   it->finish_cb = finish_cb;
1269   it->finish_cb_cls = finish_cb_cls;
1270   it->tr_cb = proc;
1271   it->cls = proc_cls;
1272   it->r_id = rid;
1273   GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head,
1274                                     h->ticket_it_tail,
1275                                     it);
1276   env = GNUNET_MQ_msg (msg,
1277                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START);
1278   msg->id = htonl (rid);
1279   msg->identity = *identity;
1280   msg->is_audience = htonl (GNUNET_YES);
1281   if (NULL == h->mq)
1282     it->env = env;
1283   else
1284     GNUNET_MQ_send (h->mq,
1285                     env);
1286   return it;
1287
1288
1289 }
1290
1291 /**
1292  * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_ticket_iteration_start
1293  * for the next record.
1294  *
1295  * @param it the iterator
1296  */
1297 void
1298 GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it)
1299 {
1300   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1301   struct TicketIterationNextMessage *msg;
1302   struct GNUNET_MQ_Envelope *env;
1303
1304   env = GNUNET_MQ_msg (msg,
1305                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT);
1306   msg->id = htonl (it->r_id);
1307   GNUNET_MQ_send (h->mq,
1308                   env);
1309 }
1310
1311
1312 /**
1313  * Stops iteration and releases the idp handle for further calls.  Must
1314  * be called on any iteration that has not yet completed prior to calling
1315  * #GNUNET_IDENTITY_PROVIDER_disconnect.
1316  *
1317  * @param it the iterator
1318  */
1319 void
1320 GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it)
1321 {
1322   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1323   struct GNUNET_MQ_Envelope *env;
1324   struct TicketIterationStopMessage *msg;
1325
1326   if (NULL != h->mq)
1327   {
1328     env = GNUNET_MQ_msg (msg,
1329                          GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP);
1330     msg->id = htonl (it->r_id);
1331     GNUNET_MQ_send (h->mq,
1332                     env);
1333   }
1334   GNUNET_free (it);
1335 }
1336
1337 /**
1338  * Revoked an issued ticket. The relying party will be unable to retrieve
1339  * updated attributes.
1340  *
1341  * @param h the identity provider to use
1342  * @param identity the issuing identity
1343  * @param ticket the ticket to revoke
1344  * @param cb the callback
1345  * @param cb_cls the callback closure
1346  * @return handle to abort the operation
1347  */
1348 struct GNUNET_IDENTITY_PROVIDER_Operation *
1349 GNUNET_IDENTITY_PROVIDER_ticket_revoke (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1350                                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1351                                         const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
1352                                         GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cb,
1353                                         void *cb_cls)
1354 {
1355   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
1356   struct GNUNET_MQ_Envelope *env;
1357   struct RevokeTicketMessage *msg;
1358   uint32_t rid;
1359
1360   rid = h->r_id_gen++;
1361   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
1362   op->h = h;
1363   op->rvk_cb = cb;
1364   op->cls = cb_cls;
1365   op->r_id = rid;
1366   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1367                                     h->op_tail,
1368                                     op);
1369   env = GNUNET_MQ_msg_extra (msg,
1370                              sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket),
1371                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET);
1372   msg->id = htonl (rid);
1373   msg->identity = *identity;
1374   memcpy (&msg[1],
1375           ticket,
1376           sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket));
1377   if (NULL == h->mq)
1378     op->env = env;
1379   else
1380     GNUNET_MQ_send (h->mq,
1381                     env);
1382   return op;
1383 }
1384
1385
1386
1387 /* end of identity_provider_api.c */