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