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