Merge branch 'master' of git+ssh://gnunet.org/gnunet
[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
380
381 /**
382  * Generic error handler, called with the appropriate error code and
383  * the same closure specified at the creation of the message queue.
384  * Not every message queue implementation supports an error handler.
385  *
386  * @param cls closure with the `struct GNUNET_GNS_Handle *`
387  * @param error error code
388  */
389 static void
390 mq_error_handler (void *cls,
391                   enum GNUNET_MQ_Error error)
392 {
393   struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls;
394   force_reconnect (handle);
395 }
396
397 /**
398  * Handle an incoming message of type
399  * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE
400  *
401  * @param cls
402  * @param msg the message we received
403  */
404 static void
405 handle_attribute_store_response (void *cls,
406                               const struct AttributeStoreResultMessage *msg)
407 {
408   struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls;
409   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
410   uint32_t r_id = ntohl (msg->id);
411   int res;
412   const char *emsg;
413
414   for (op = h->op_head; NULL != op; op = op->next)
415     if (op->r_id == r_id)
416       break;
417   if (NULL == op)
418     return;
419
420   res = ntohl (msg->op_result);
421   LOG (GNUNET_ERROR_TYPE_DEBUG,
422        "Received ATTRIBUTE_STORE_RESPONSE with result %d\n",
423        res);
424
425   /* TODO: add actual error message to response... */
426   if (GNUNET_SYSERR == res)
427     emsg = _("failed to store record\n");
428   else
429     emsg = NULL;
430   if (NULL != op->as_cb)
431     op->as_cb (op->cls,
432               res,
433               emsg);
434   GNUNET_CONTAINER_DLL_remove (h->op_head,
435                                h->op_tail,
436                                op);
437   GNUNET_free (op);
438
439 }
440
441
442 /**
443  * Handle an incoming message of type
444  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT
445  *
446  * @param cls
447  * @param msg the message we received
448  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
449  */
450 static int
451 check_consume_ticket_result (void *cls,
452                              const struct ConsumeTicketResultMessage *msg)
453 {
454   size_t msg_len;
455   size_t attrs_len;
456
457   msg_len = ntohs (msg->header.size);
458   attrs_len = ntohs (msg->attrs_len);
459   if (msg_len != sizeof (struct ConsumeTicketResultMessage) + attrs_len)
460   {
461     GNUNET_break (0);
462     return GNUNET_SYSERR;
463   }
464   return GNUNET_OK;
465 }
466
467
468 /**
469  * Handle an incoming message of type
470  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT
471  *
472  * @param cls
473  * @param msg the message we received
474  */
475 static void
476 handle_consume_ticket_result (void *cls,
477                               const struct ConsumeTicketResultMessage *msg)
478 {
479   struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls;
480   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
481   size_t attrs_len;
482   uint32_t r_id = ntohl (msg->id);
483
484   attrs_len = ntohs (msg->attrs_len);
485   LOG (GNUNET_ERROR_TYPE_DEBUG,
486        "Processing attribute result.\n");
487
488
489   for (op = h->op_head; NULL != op; op = op->next)
490     if (op->r_id == r_id)
491       break;
492   if (NULL == op)
493     return;
494
495   {
496     struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs;
497     struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
498     attrs = GNUNET_IDENTITY_ATTRIBUTE_list_deserialize ((char*)&msg[1],
499                                         attrs_len);
500     if (NULL != op->ar_cb)
501     {
502       if (NULL == attrs)
503       {
504         op->ar_cb (op->cls,
505                    &msg->identity,
506                    NULL);
507       }
508       else
509       {
510         for (le = attrs->list_head; NULL != le; le = le->next)
511           op->ar_cb (op->cls,
512                      &msg->identity,
513                      le->claim);
514         GNUNET_IDENTITY_ATTRIBUTE_list_destroy (attrs);
515       }
516     }
517     op->ar_cb (op->cls,
518                NULL,
519                NULL);
520     GNUNET_CONTAINER_DLL_remove (h->op_head,
521                                  h->op_tail,
522                                  op);
523     GNUNET_free (op);
524     return;
525   }
526   GNUNET_assert (0);
527 }
528
529
530 /**
531  * Handle an incoming message of type
532  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT
533  *
534  * @param cls
535  * @param msg the message we received
536  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
537  */
538 static int
539 check_attribute_result (void *cls,
540                         const struct AttributeResultMessage *msg)
541 {
542   size_t msg_len;
543   size_t attr_len;
544
545   msg_len = ntohs (msg->header.size);
546   attr_len = ntohs (msg->attr_len);
547   if (msg_len != sizeof (struct AttributeResultMessage) + attr_len)
548   {
549     GNUNET_break (0);
550     return GNUNET_SYSERR;
551   }
552   return GNUNET_OK;
553 }
554
555
556 /**
557  * Handle an incoming message of type
558  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT
559  *
560  * @param cls
561  * @param msg the message we received
562  */
563 static void
564 handle_attribute_result (void *cls,
565                          const struct AttributeResultMessage *msg)
566 {
567   static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy;
568   struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls;
569   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it;
570   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
571   size_t attr_len;
572   uint32_t r_id = ntohl (msg->id);
573
574   attr_len = ntohs (msg->attr_len);
575   LOG (GNUNET_ERROR_TYPE_DEBUG,
576        "Processing attribute result.\n");
577
578
579   for (it = h->it_head; NULL != it; it = it->next)
580     if (it->r_id == r_id)
581       break;
582   for (op = h->op_head; NULL != op; op = op->next)
583     if (op->r_id == r_id)
584       break;
585   if ((NULL == it) && (NULL == op))
586     return;
587
588   if ( (0 == (memcmp (&msg->identity,
589                       &identity_dummy,
590                       sizeof (identity_dummy)))) )
591   {
592     if ((NULL == it) && (NULL == op))
593     {
594       GNUNET_break (0);
595       force_reconnect (h);
596       return;
597     }
598     if (NULL != it)
599     {
600       if (NULL != it->finish_cb)
601         it->finish_cb (it->finish_cb_cls);
602       free_it (it);
603     }
604     if (NULL != op) 
605     {
606       if (NULL != op->ar_cb)
607         op->ar_cb (op->cls,
608                    NULL,
609                    NULL);
610       GNUNET_CONTAINER_DLL_remove (h->op_head,
611                                    h->op_tail,
612                                    op);
613       GNUNET_free (op);
614
615     }
616     return;
617   }
618
619   {
620     struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr;
621     attr = GNUNET_IDENTITY_ATTRIBUTE_deserialize ((char*)&msg[1],
622                                                   attr_len);
623     if (NULL != it)
624     {
625       if (NULL != it->proc)
626         it->proc (it->proc_cls,
627                   &msg->identity,
628                   attr);
629     } else if (NULL != op)
630     {
631       if (NULL != op->ar_cb)
632         op->ar_cb (op->cls,
633                    &msg->identity,
634                    attr);
635
636     }
637     GNUNET_free (attr);
638     return;
639   }
640   GNUNET_assert (0);
641 }
642
643 /**
644  * Handle an incoming message of type
645  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT
646  *
647  * @param cls
648  * @param msg the message we received
649  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
650  */
651 static int
652 check_ticket_result (void *cls,
653                      const struct TicketResultMessage *msg)
654 {
655   size_t msg_len;
656
657   msg_len = ntohs (msg->header.size);
658   if (msg_len < sizeof (struct TicketResultMessage))
659   {
660     GNUNET_break (0);
661     return GNUNET_SYSERR;
662   }
663   return GNUNET_OK;
664 }
665
666
667
668 /**
669  * Handle an incoming message of type
670  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT
671  *
672  * @param cls
673  * @param msg the message we received
674  */
675 static void
676 handle_ticket_result (void *cls,
677                       const struct TicketResultMessage *msg)
678 {
679   struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls;
680   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
681   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it;
682   const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket;
683   uint32_t r_id = ntohl (msg->id);
684   size_t msg_len;
685
686   for (op = handle->op_head; NULL != op; op = op->next)
687     if (op->r_id == r_id)
688       break;
689   for (it = handle->ticket_it_head; NULL != it; it = it->next)
690     if (it->r_id == r_id)
691       break;
692   if ((NULL == op) && (NULL == it))
693     return;
694   msg_len = ntohs (msg->header.size);
695   if (NULL != op)
696   {
697     GNUNET_CONTAINER_DLL_remove (handle->op_head,
698                                  handle->op_tail,
699                                  op);
700     if (msg_len == sizeof (struct TicketResultMessage))
701     {
702       if (NULL != op->tr_cb)
703         op->tr_cb (op->cls, NULL);
704     } else {
705       ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket *)&msg[1];
706       if (NULL != op->tr_cb)
707         op->tr_cb (op->cls, ticket);
708     }
709     GNUNET_free (op);
710     return;
711   } else if (NULL != it) {
712     if (msg_len == sizeof (struct TicketResultMessage))
713     {
714       if (NULL != it->tr_cb)
715         GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head,
716                                      handle->ticket_it_tail,
717                                      it);
718       it->finish_cb (it->finish_cb_cls);
719       GNUNET_free (it);
720     } else {
721       ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket *)&msg[1];
722       if (NULL != it->tr_cb)
723         it->tr_cb (it->cls, ticket);
724     }
725     return;
726   }
727   GNUNET_break (0);
728 }
729
730 /**
731  * Handle an incoming message of type
732  * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT
733  *
734  * @param cls
735  * @param msg the message we received
736  */
737 static void
738 handle_revoke_ticket_result (void *cls,
739                              const struct RevokeTicketResultMessage *msg)
740 {
741   struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls;
742   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
743   uint32_t r_id = ntohl (msg->id);
744   int32_t success;
745
746   LOG (GNUNET_ERROR_TYPE_DEBUG,
747        "Processing revocation result.\n");
748
749
750   for (op = h->op_head; NULL != op; op = op->next)
751     if (op->r_id == r_id)
752       break;
753   if (NULL == op)
754     return;
755   success = ntohl (msg->success);
756   {
757     if (NULL != op->rvk_cb)
758     {
759       op->rvk_cb (op->cls,
760                   success,
761                   NULL);
762     }
763     GNUNET_CONTAINER_DLL_remove (h->op_head,
764                                  h->op_tail,
765                                  op);
766     GNUNET_free (op);
767     return;
768   }
769   GNUNET_assert (0);
770 }
771
772
773
774 /**
775  * Try again to connect to the service.
776  *
777  * @param h handle to the identity provider service.
778  */
779 static void
780 reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h)
781 {
782   struct GNUNET_MQ_MessageHandler handlers[] = {
783     GNUNET_MQ_hd_fixed_size (attribute_store_response,
784                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE_RESPONSE,
785                              struct AttributeStoreResultMessage,
786                              h),
787     GNUNET_MQ_hd_var_size (attribute_result,
788                            GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT,
789                            struct AttributeResultMessage,
790                            h),
791     GNUNET_MQ_hd_var_size (ticket_result,
792                            GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT,
793                            struct TicketResultMessage,
794                            h),
795     GNUNET_MQ_hd_var_size (consume_ticket_result,
796                            GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT,
797                            struct ConsumeTicketResultMessage,
798                            h),
799     GNUNET_MQ_hd_fixed_size (revoke_ticket_result,
800                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT,
801                              struct RevokeTicketResultMessage,
802                              h),
803     GNUNET_MQ_handler_end ()
804   };
805   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
806
807   GNUNET_assert (NULL == h->mq);
808   LOG (GNUNET_ERROR_TYPE_DEBUG,
809        "Connecting to identity provider service.\n");
810
811   h->mq = GNUNET_CLIENT_connect (h->cfg,
812                                  "identity-provider",
813                                  handlers,
814                                  &mq_error_handler,
815                                  h);
816   if (NULL == h->mq)
817     return;
818   for (op = h->op_head; NULL != op; op = op->next)
819     GNUNET_MQ_send_copy (h->mq,
820                          op->env);
821 }
822
823
824 /**
825  * Connect to the identity provider service.
826  *
827  * @param cfg the configuration to use
828  * @return handle to use
829  */
830 struct GNUNET_IDENTITY_PROVIDER_Handle *
831 GNUNET_IDENTITY_PROVIDER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
832 {
833   struct GNUNET_IDENTITY_PROVIDER_Handle *h;
834
835   h = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Handle);
836   h->cfg = cfg;
837   reconnect (h);
838   if (NULL == h->mq)
839   {
840     GNUNET_free (h);
841     return NULL;
842   }
843   return h;
844 }
845
846
847 /**
848  * Cancel an operation. Note that the operation MAY still
849  * be executed; this merely cancels the continuation; if the request
850  * was already transmitted, the service may still choose to complete
851  * the operation.
852  *
853  * @param op operation to cancel
854  */
855 void
856 GNUNET_IDENTITY_PROVIDER_cancel (struct GNUNET_IDENTITY_PROVIDER_Operation *op)
857 {
858   struct GNUNET_IDENTITY_PROVIDER_Handle *h = op->h;
859
860   GNUNET_CONTAINER_DLL_remove (h->op_head,
861                                h->op_tail,
862                                op);
863   GNUNET_MQ_discard (op->env);
864   GNUNET_free (op);
865 }
866
867
868 /**
869  * Disconnect from service
870  *
871  * @param h handle to destroy
872  */
873 void
874 GNUNET_IDENTITY_PROVIDER_disconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h)
875 {
876   GNUNET_assert (NULL != h);
877   if (NULL != h->mq)
878   {
879     GNUNET_MQ_destroy (h->mq);
880     h->mq = NULL;
881   }
882   if (NULL != h->reconnect_task)
883   {
884     GNUNET_SCHEDULER_cancel (h->reconnect_task);
885     h->reconnect_task = NULL;
886   }
887   GNUNET_assert (NULL == h->op_head);
888   GNUNET_free (h);
889 }
890
891 /**
892  * Store an attribute.  If the attribute is already present,
893  * it is replaced with the new attribute.
894  *
895  * @param h handle to the identity provider
896  * @param pkey private key of the identity
897  * @param attr the attribute value
898  * @param cont continuation to call when done
899  * @param cont_cls closure for @a cont
900  * @return handle to abort the request
901  */
902 struct GNUNET_IDENTITY_PROVIDER_Operation *
903 GNUNET_IDENTITY_PROVIDER_attribute_store (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
904                                           const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
905                                           const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr,
906                                           GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cont,
907                                           void *cont_cls)
908 {
909   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
910   struct AttributeStoreMessage *sam;
911   size_t attr_len;
912
913   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
914   op->h = h;
915   op->as_cb = cont;
916   op->cls = cont_cls;
917   op->r_id = h->r_id_gen++;
918   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
919                                     h->op_tail,
920                                     op);
921   attr_len = GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (attr);
922   op->env = GNUNET_MQ_msg_extra (sam,
923                                  attr_len,
924                                  GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE);
925   sam->identity = *pkey;
926   sam->id = htonl (op->r_id);
927
928   GNUNET_IDENTITY_ATTRIBUTE_serialize (attr,
929                        (char*)&sam[1]);
930
931   sam->attr_len = htons (attr_len);
932   if (NULL != h->mq)
933     GNUNET_MQ_send_copy (h->mq,
934                          op->env);
935   return op;
936
937 }
938
939
940 /**
941  * List all attributes for a local identity. 
942  * This MUST lock the `struct GNUNET_IDENTITY_PROVIDER_Handle`
943  * for any other calls than #GNUNET_IDENTITY_PROVIDER_get_attributes_next() and
944  * #GNUNET_IDENTITY_PROVIDER_get_attributes_stop. @a proc will be called once
945  * immediately, and then again after
946  * #GNUNET_IDENTITY_PROVIDER_get_attributes_next() is invoked.
947  *
948  * On error (disconnect), @a error_cb will be invoked.
949  * On normal completion, @a finish_cb proc will be
950  * invoked.
951  *
952  * @param h handle to the idp
953  * @param identity identity to access
954  * @param error_cb function to call on error (i.e. disconnect),
955  *        the handle is afterwards invalid
956  * @param error_cb_cls closure for @a error_cb
957  * @param proc function to call on each attribute; it
958  *        will be called repeatedly with a value (if available)
959  * @param proc_cls closure for @a proc
960  * @param finish_cb function to call on completion
961  *        the handle is afterwards invalid
962  * @param finish_cb_cls closure for @a finish_cb
963  * @return an iterator handle to use for iteration
964  */
965 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *
966 GNUNET_IDENTITY_PROVIDER_get_attributes_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
967                                                const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
968                                                GNUNET_SCHEDULER_TaskCallback error_cb,
969                                                void *error_cb_cls,
970                                                GNUNET_IDENTITY_PROVIDER_AttributeResult proc,
971                                                void *proc_cls,
972                                                GNUNET_SCHEDULER_TaskCallback finish_cb,
973                                                void *finish_cb_cls)
974 {
975   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it;
976   struct GNUNET_MQ_Envelope *env;
977   struct AttributeIterationStartMessage *msg;
978   uint32_t rid;
979
980   rid = h->r_id_gen++;
981   it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator);
982   it->h = h;
983   it->error_cb = error_cb;
984   it->error_cb_cls = error_cb_cls;
985   it->finish_cb = finish_cb;
986   it->finish_cb_cls = finish_cb_cls;
987   it->proc = proc;
988   it->proc_cls = proc_cls;
989   it->r_id = rid;
990   it->identity = *identity;
991   GNUNET_CONTAINER_DLL_insert_tail (h->it_head,
992                                     h->it_tail,
993                                     it);
994   env = GNUNET_MQ_msg (msg,
995                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_START);
996   msg->id = htonl (rid);
997   msg->identity = *identity;
998   if (NULL == h->mq)
999     it->env = env;
1000   else
1001     GNUNET_MQ_send (h->mq,
1002                     env);
1003   return it;
1004 }
1005
1006
1007 /**
1008  * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_get_attributes_start
1009  * for the next record.
1010  *
1011  * @param it the iterator
1012  */
1013 void
1014 GNUNET_IDENTITY_PROVIDER_get_attributes_next (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it)
1015 {
1016   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1017   struct AttributeIterationNextMessage *msg;
1018   struct GNUNET_MQ_Envelope *env;
1019
1020   env = GNUNET_MQ_msg (msg,
1021                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_NEXT);
1022   msg->id = htonl (it->r_id);
1023   GNUNET_MQ_send (h->mq,
1024                   env);
1025 }
1026
1027
1028 /**
1029  * Stops iteration and releases the idp handle for further calls.  Must
1030  * be called on any iteration that has not yet completed prior to calling
1031  * #GNUNET_IDENTITY_PROVIDER_disconnect.
1032  *
1033  * @param it the iterator
1034  */
1035 void
1036 GNUNET_IDENTITY_PROVIDER_get_attributes_stop (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it)
1037 {
1038   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1039   struct GNUNET_MQ_Envelope *env;
1040   struct AttributeIterationStopMessage *msg;
1041
1042   if (NULL != h->mq)
1043   {
1044     env = GNUNET_MQ_msg (msg,
1045                          GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_STOP);
1046     msg->id = htonl (it->r_id);
1047     GNUNET_MQ_send (h->mq,
1048                     env);
1049   }
1050   free_it (it);
1051 }
1052
1053
1054 /** TODO
1055  * Issues a ticket to another identity. The identity may use
1056  * @GNUNET_IDENTITY_PROVIDER_authorization_ticket_consume to consume the ticket
1057  * and retrieve the attributes specified in the AttributeList.
1058  *
1059  * @param h the identity provider to use
1060  * @param iss the issuing identity
1061  * @param rp the subject of the ticket (the relying party)
1062  * @param attrs the attributes that the relying party is given access to
1063  * @param cb the callback
1064  * @param cb_cls the callback closure
1065  * @return handle to abort the operation
1066  */
1067 struct GNUNET_IDENTITY_PROVIDER_Operation *
1068 GNUNET_IDENTITY_PROVIDER_ticket_issue (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1069                                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss,
1070                                        const struct GNUNET_CRYPTO_EcdsaPublicKey *rp,
1071                                        const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs,
1072                                        GNUNET_IDENTITY_PROVIDER_TicketCallback cb,
1073                                        void *cb_cls)
1074 {
1075   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
1076   struct IssueTicketMessage *tim;
1077   size_t attr_len;
1078
1079   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
1080   op->h = h;
1081   op->tr_cb = cb;
1082   op->cls = cb_cls;
1083   op->r_id = h->r_id_gen++;
1084   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1085                                     h->op_tail,
1086                                     op);
1087   attr_len = GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (attrs);
1088   op->env = GNUNET_MQ_msg_extra (tim,
1089                                  attr_len,
1090                                  GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_TICKET);
1091   tim->identity = *iss;
1092   tim->rp = *rp;
1093   tim->id = htonl (op->r_id);
1094
1095   GNUNET_IDENTITY_ATTRIBUTE_list_serialize (attrs,
1096                             (char*)&tim[1]);
1097
1098   tim->attr_len = htons (attr_len);
1099   if (NULL != h->mq)
1100     GNUNET_MQ_send_copy (h->mq,
1101                          op->env);
1102   return op;
1103 }
1104
1105 /**
1106  * Consumes an issued ticket. The ticket is persisted
1107  * and used to retrieve identity information from the issuer
1108  *
1109  * @param h the identity provider to use
1110  * @param identity the identity that is the subject of the issued ticket (the relying party)
1111  * @param ticket the issued ticket to consume
1112  * @param cb the callback to call
1113  * @param cb_cls the callback closure
1114  * @return handle to abort the operation
1115  */
1116 struct GNUNET_IDENTITY_PROVIDER_Operation *
1117 GNUNET_IDENTITY_PROVIDER_ticket_consume (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1118                                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1119                                          const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
1120                                          GNUNET_IDENTITY_PROVIDER_AttributeResult cb,
1121                                          void *cb_cls)
1122 {
1123   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
1124   struct ConsumeTicketMessage *ctm;
1125
1126   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
1127   op->h = h;
1128   op->ar_cb = cb;
1129   op->cls = cb_cls;
1130   op->r_id = h->r_id_gen++;
1131   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1132                                     h->op_tail,
1133                                     op);
1134   op->env = GNUNET_MQ_msg_extra (ctm,
1135                                  sizeof (const struct GNUNET_IDENTITY_PROVIDER_Ticket),
1136                                  GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET);
1137   ctm->identity = *identity;
1138   ctm->id = htonl (op->r_id);
1139
1140   GNUNET_memcpy ((char*)&ctm[1],
1141                  ticket,
1142                  sizeof (const struct GNUNET_IDENTITY_PROVIDER_Ticket));
1143
1144   if (NULL != h->mq)
1145     GNUNET_MQ_send_copy (h->mq,
1146                          op->env);
1147   return op;
1148
1149 }
1150
1151
1152 /**
1153  * Lists all tickets that have been issued to remote
1154  * identites (relying parties)
1155  *
1156  * @param h the identity provider to use
1157  * @param identity the issuing identity
1158  * @param error_cb function to call on error (i.e. disconnect),
1159  *        the handle is afterwards invalid
1160  * @param error_cb_cls closure for @a error_cb
1161  * @param proc function to call on each ticket; it
1162  *        will be called repeatedly with a value (if available)
1163  * @param proc_cls closure for @a proc
1164  * @param finish_cb function to call on completion
1165  *        the handle is afterwards invalid
1166  * @param finish_cb_cls closure for @a finish_cb
1167  * @return an iterator handle to use for iteration
1168  */
1169 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *
1170 GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1171                                                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1172                                                  GNUNET_SCHEDULER_TaskCallback error_cb,
1173                                                  void *error_cb_cls,
1174                                                  GNUNET_IDENTITY_PROVIDER_TicketCallback proc,
1175                                                  void *proc_cls,
1176                                                  GNUNET_SCHEDULER_TaskCallback finish_cb,
1177                                                  void *finish_cb_cls)
1178 {
1179   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it;
1180   struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
1181   struct GNUNET_MQ_Envelope *env;
1182   struct TicketIterationStartMessage *msg;
1183   uint32_t rid;
1184
1185   GNUNET_CRYPTO_ecdsa_key_get_public (identity,
1186                                       &identity_pub);
1187   rid = h->r_id_gen++;
1188   it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_TicketIterator);
1189   it->h = h;
1190   it->error_cb = error_cb;
1191   it->error_cb_cls = error_cb_cls;
1192   it->finish_cb = finish_cb;
1193   it->finish_cb_cls = finish_cb_cls;
1194   it->tr_cb = proc;
1195   it->cls = proc_cls;
1196   it->r_id = rid;
1197   GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head,
1198                                     h->ticket_it_tail,
1199                                     it);
1200   env = GNUNET_MQ_msg (msg,
1201                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START);
1202   msg->id = htonl (rid);
1203   msg->identity = identity_pub;
1204   msg->is_audience = htonl (GNUNET_NO);
1205   if (NULL == h->mq)
1206     it->env = env;
1207   else
1208     GNUNET_MQ_send (h->mq,
1209                     env);
1210   return it;
1211
1212 }
1213
1214
1215 /**
1216  * Lists all tickets that have been issued to remote
1217  * identites (relying parties)
1218  *
1219  * @param h the identity provider to use
1220  * @param identity the issuing identity
1221  * @param error_cb function to call on error (i.e. disconnect),
1222  *        the handle is afterwards invalid
1223  * @param error_cb_cls closure for @a error_cb
1224  * @param proc function to call on each ticket; it
1225  *        will be called repeatedly with a value (if available)
1226  * @param proc_cls closure for @a proc
1227  * @param finish_cb function to call on completion
1228  *        the handle is afterwards invalid
1229  * @param finish_cb_cls closure for @a finish_cb
1230  * @return an iterator handle to use for iteration
1231  */
1232 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *
1233 GNUNET_IDENTITY_PROVIDER_ticket_iteration_start_rp (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1234                                                     const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1235                                                     GNUNET_SCHEDULER_TaskCallback error_cb,
1236                                                     void *error_cb_cls,
1237                                                     GNUNET_IDENTITY_PROVIDER_TicketCallback proc,
1238                                                     void *proc_cls,
1239                                                     GNUNET_SCHEDULER_TaskCallback finish_cb,
1240                                                     void *finish_cb_cls)
1241 {
1242   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it;
1243   struct GNUNET_MQ_Envelope *env;
1244   struct TicketIterationStartMessage *msg;
1245   uint32_t rid;
1246
1247   rid = h->r_id_gen++;
1248   it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_TicketIterator);
1249   it->h = h;
1250   it->error_cb = error_cb;
1251   it->error_cb_cls = error_cb_cls;
1252   it->finish_cb = finish_cb;
1253   it->finish_cb_cls = finish_cb_cls;
1254   it->tr_cb = proc;
1255   it->cls = proc_cls;
1256   it->r_id = rid;
1257   GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head,
1258                                     h->ticket_it_tail,
1259                                     it);
1260   env = GNUNET_MQ_msg (msg,
1261                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START);
1262   msg->id = htonl (rid);
1263   msg->identity = *identity;
1264   msg->is_audience = htonl (GNUNET_YES);
1265   if (NULL == h->mq)
1266     it->env = env;
1267   else
1268     GNUNET_MQ_send (h->mq,
1269                     env);
1270   return it;
1271
1272
1273 }
1274
1275 /**
1276  * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_ticket_iteration_start
1277  * for the next record.
1278  *
1279  * @param it the iterator
1280  */
1281 void
1282 GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it)
1283 {
1284   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1285   struct TicketIterationNextMessage *msg;
1286   struct GNUNET_MQ_Envelope *env;
1287
1288   env = GNUNET_MQ_msg (msg,
1289                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT);
1290   msg->id = htonl (it->r_id);
1291   GNUNET_MQ_send (h->mq,
1292                   env);
1293 }
1294
1295
1296 /**
1297  * Stops iteration and releases the idp handle for further calls.  Must
1298  * be called on any iteration that has not yet completed prior to calling
1299  * #GNUNET_IDENTITY_PROVIDER_disconnect.
1300  *
1301  * @param it the iterator
1302  */
1303 void
1304 GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it)
1305 {
1306   struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h;
1307   struct GNUNET_MQ_Envelope *env;
1308   struct TicketIterationStopMessage *msg;
1309
1310   if (NULL != h->mq)
1311   {
1312     env = GNUNET_MQ_msg (msg,
1313                          GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP);
1314     msg->id = htonl (it->r_id);
1315     GNUNET_MQ_send (h->mq,
1316                     env);
1317   }
1318   GNUNET_free (it);
1319 }
1320
1321 /**
1322  * Revoked an issued ticket. The relying party will be unable to retrieve
1323  * updated attributes.
1324  *
1325  * @param h the identity provider to use
1326  * @param identity the issuing identity
1327  * @param ticket the ticket to revoke
1328  * @param cb the callback
1329  * @param cb_cls the callback closure
1330  * @return handle to abort the operation
1331  */
1332 struct GNUNET_IDENTITY_PROVIDER_Operation *
1333 GNUNET_IDENTITY_PROVIDER_ticket_revoke (struct GNUNET_IDENTITY_PROVIDER_Handle *h,
1334                                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1335                                         const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
1336                                         GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cb,
1337                                         void *cb_cls)
1338 {
1339   struct GNUNET_IDENTITY_PROVIDER_Operation *op;
1340   struct GNUNET_MQ_Envelope *env;
1341   struct RevokeTicketMessage *msg;
1342   uint32_t rid;
1343
1344   rid = h->r_id_gen++;
1345   op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation);
1346   op->h = h;
1347   op->rvk_cb = cb;
1348   op->cls = cb_cls;
1349   op->r_id = rid;
1350   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1351                                     h->op_tail,
1352                                     op);
1353   env = GNUNET_MQ_msg_extra (msg,
1354                              sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket),
1355                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET);
1356   msg->id = htonl (rid);
1357   msg->identity = *identity;
1358   memcpy (&msg[1],
1359           ticket,
1360           sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket));
1361   if (NULL == h->mq)
1362     op->env = env;
1363   else
1364     GNUNET_MQ_send (h->mq,
1365                     env);
1366   return op;
1367 }
1368
1369
1370
1371 /* end of identity_provider_api.c */