aboutsummaryrefslogtreecommitdiff
path: root/src/identity-provider/identity_provider_api.c
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2016-01-08 18:59:47 +0000
committerMartin Schanzenbach <mschanzenbach@posteo.de>2016-01-08 18:59:47 +0000
commit35262a0fe27afccb154122f113adcc75947ee45d (patch)
tree5b1259067c9da96e60c2a303415b222a4c383319 /src/identity-provider/identity_provider_api.c
parent1b67c9c5424c96ff4e30d12b8d58cec315f000a1 (diff)
downloadgnunet-35262a0fe27afccb154122f113adcc75947ee45d.tar.gz
gnunet-35262a0fe27afccb154122f113adcc75947ee45d.zip
- More heavy refactoring. Probably lots of broken things to see here.
Diffstat (limited to 'src/identity-provider/identity_provider_api.c')
-rw-r--r--src/identity-provider/identity_provider_api.c611
1 files changed, 611 insertions, 0 deletions
diff --git a/src/identity-provider/identity_provider_api.c b/src/identity-provider/identity_provider_api.c
new file mode 100644
index 000000000..c22151534
--- /dev/null
+++ b/src/identity-provider/identity_provider_api.c
@@ -0,0 +1,611 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 Christian Grothoff (and other contributing authors)
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_identity_provider_service.h"
31#include "identity_provider.h"
32
33#define LOG(kind,...) GNUNET_log_from (kind, "identity-api",__VA_ARGS__)
34
35
36
37/**
38 * Handle for an operation with the service.
39 */
40struct GNUNET_IDENTITY_PROVIDER_Operation
41{
42
43 /**
44 * Main handle.
45 */
46 struct GNUNET_IDENTITY_PROVIDER_Handle *h;
47
48 /**
49 * We keep operations in a DLL.
50 */
51 struct GNUNET_IDENTITY_PROVIDER_Operation *next;
52
53 /**
54 * We keep operations in a DLL.
55 */
56 struct GNUNET_IDENTITY_PROVIDER_Operation *prev;
57
58 /**
59 * Message to send to the service.
60 * Allocated at the end of this struct.
61 */
62 const struct GNUNET_MessageHeader *msg;
63
64 /**
65 * Continuation to invoke with the result of the transmission; @e cb
66 * will be NULL in this case.
67 */
68 GNUNET_IDENTITY_PROVIDER_ExchangeCallback ex_cb;
69
70 /**
71 * Continuation to invoke with the result of the transmission for
72 * 'issue' operations (@e cont will be NULL in this case).
73 */
74 GNUNET_IDENTITY_PROVIDER_IssueCallback iss_cb;
75
76 /**
77 * Closure for @e cont or @e cb.
78 */
79 void *cls;
80
81};
82
83
84/**
85 * Handle for the service.
86 */
87struct GNUNET_IDENTITY_PROVIDER_Handle
88{
89 /**
90 * Configuration to use.
91 */
92 const struct GNUNET_CONFIGURATION_Handle *cfg;
93
94 /**
95 * Socket (if available).
96 */
97 struct GNUNET_CLIENT_Connection *client;
98
99 /**
100 * Function to call when we receive updates.
101 */
102 GNUNET_IDENTITY_PROVIDER_Callback cb;
103
104 /**
105 * Closure for 'cb'.
106 */
107 void *cb_cls;
108
109 /**
110 * Head of active operations.
111 */
112 struct GNUNET_IDENTITY_PROVIDER_Operation *op_head;
113
114 /**
115 * Tail of active operations.
116 */
117 struct GNUNET_IDENTITY_PROVIDER_Operation *op_tail;
118
119 /**
120 * Currently pending transmission request, or NULL for none.
121 */
122 struct GNUNET_CLIENT_TransmitHandle *th;
123
124 /**
125 * Task doing exponential back-off trying to reconnect.
126 */
127 struct GNUNET_SCHEDULER_Task * reconnect_task;
128
129 /**
130 * Time for next connect retry.
131 */
132 struct GNUNET_TIME_Relative reconnect_delay;
133
134 /**
135 * Are we polling for incoming messages right now?
136 */
137 int in_receive;
138
139};
140
141
142/**
143 * Try again to connect to the service.
144 *
145 * @param cls handle to the service.
146 * @param tc scheduler context
147 */
148static void
149reconnect (void *cls,
150 const struct GNUNET_SCHEDULER_TaskContext *tc);
151
152
153/**
154 * Reschedule a connect attempt to the service.
155 *
156 * @param h transport service to reconnect
157 */
158static void
159reschedule_connect (struct GNUNET_IDENTITY_Handle *h)
160{
161 GNUNET_assert (h->reconnect_task == NULL);
162
163 if (NULL != h->th)
164 {
165 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
166 h->th = NULL;
167 }
168 if (NULL != h->client)
169 {
170 GNUNET_CLIENT_disconnect (h->client);
171 h->client = NULL;
172 }
173 h->in_receive = GNUNET_NO;
174 LOG (GNUNET_ERROR_TYPE_DEBUG,
175 "Scheduling task to reconnect to identity provider service in %s.\n",
176 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
177 h->reconnect_task =
178 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
179 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
180}
181
182
183/**
184 * Type of a function to call when we receive a message
185 * from the service.
186 *
187 * @param cls closure
188 * @param msg message received, NULL on timeout or fatal error
189 */
190static void
191message_handler (void *cls,
192 const struct GNUNET_MessageHeader *msg)
193{
194 struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls;
195 struct GNUNET_IDENTITY_PROVIDER_Operation *op;
196 struct GNUNET_IDENTITY_PROVIDER_Token token;
197 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
198 const struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
199 const struct GNUNET_IDENTITY_ExchangeResultMessage *erm;
200 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
201 struct GNUNET_HashCode id;
202 const char *str;
203 uint16_t size;
204 uint16_t name_len;
205
206 if (NULL == msg)
207 {
208 reschedule_connect (h);
209 return;
210 }
211 LOG (GNUNET_ERROR_TYPE_DEBUG,
212 "Received message of type %d from identity provider service\n",
213 ntohs (msg->type));
214 size = ntohs (msg->size);
215 switch (ntohs (msg->type))
216 {
217 case GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT:
218 if (size < sizeof (struct GNUNET_IDENTITY_IssueResultMessage))
219 {
220 GNUNET_break (0);
221 reschedule_connect (h);
222 return;
223 }
224 irm = (const struct GNUNET_IDENTITY_IssueResultMessage *) msg;
225 str = (const char *) &irm[1];
226 if ( (size > sizeof (struct GNUNET_IDENTITY_IssueResultMessage)) &&
227 ('\0' != str[size - sizeof (struct GNUNET_IDENTITY_IssueResultMessage) - 1]) )
228 {
229 GNUNET_break (0);
230 reschedule_connect (h);
231 return;
232 }
233 if (size == sizeof (struct GNUNET_IDENTITY_IssueResultMessage))
234 str = NULL;
235
236 op = h->op_head;
237 GNUNET_CONTAINER_DLL_remove (h->op_head,
238 h->op_tail,
239 op);
240 GNUNET_CLIENT_receive (h->client, &message_handler, h,
241 GNUNET_TIME_UNIT_FOREVER_REL);
242 ticket->data = str;
243 if (NULL != op->iss_cb)
244 op->iss_cb (op->cls, &ticket);
245 GNUNET_free (op);
246 break;
247 case GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT:
248 if (size < sizeof (struct GNUNET_IDENTITY_ExchangeResultMessage))
249 {
250 GNUNET_break (0);
251 reschedule_connect (h);
252 return;
253 }
254 erm = (const struct GNUNET_IDENTITY_ExchangeResultMessage *) msg;
255 str = (const char *) &erm[1];
256 if ( (size > sizeof (struct GNUNET_IDENTITY_ExchangeResultMessage)) &&
257 ('\0' != str[size - sizeof (struct GNUNET_IDENTITY_ExchangeResultMessage) - 1]) )
258 {
259 GNUNET_break (0);
260 reschedule_connect (h);
261 return;
262 }
263 if (size == sizeof (struct GNUNET_IDENTITY_ExchangeResultMessage))
264 str = NULL;
265
266 op = h->op_head;
267 GNUNET_CONTAINER_DLL_remove (h->op_head,
268 h->op_tail,
269 op);
270 GNUNET_CLIENT_receive (h->client, &message_handler, h,
271 GNUNET_TIME_UNIT_FOREVER_REL);
272 token->data = str;
273 if (NULL != op->ex_cb)
274 op->ex_cb (op->cls, token);
275 GNUNET_free (op);
276 break;
277
278 default:
279 GNUNET_break (0);
280 reschedule_connect (h);
281 return;
282 }
283}
284
285
286/**
287 * Schedule transmission of the next message from our queue.
288 *
289 * @param h identity handle
290 */
291static void
292transmit_next (struct GNUNET_IDENTITY_PROVIDER_Handle *h);
293
294
295/**
296 * Transmit next message to service.
297 *
298 * @param cls the `struct GNUNET_IDENTITY_PROVIDER_Handle`.
299 * @param size number of bytes available in @a buf
300 * @param buf where to copy the message
301 * @return number of bytes copied to buf
302 */
303static size_t
304send_next_message (void *cls,
305 size_t size,
306 void *buf)
307{
308 struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls;
309 struct GNUNET_IDENTITY_PROVIDER_Operation *op = h->op_head;
310 size_t ret;
311
312 h->th = NULL;
313 if (NULL == op)
314 return 0;
315 ret = ntohs (op->msg->size);
316 if (ret > size)
317 {
318 reschedule_connect (h);
319 return 0;
320 }
321 LOG (GNUNET_ERROR_TYPE_DEBUG,
322 "Sending message of type %d to identity provider service\n",
323 ntohs (op->msg->type));
324 memcpy (buf, op->msg, ret);
325 if ( (NULL == op->cont) &&
326 (NULL == op->cb) )
327 {
328 GNUNET_CONTAINER_DLL_remove (h->op_head,
329 h->op_tail,
330 op);
331 GNUNET_free (op);
332 transmit_next (h);
333 }
334 if (GNUNET_NO == h->in_receive)
335 {
336 h->in_receive = GNUNET_YES;
337 GNUNET_CLIENT_receive (h->client,
338 &message_handler, h,
339 GNUNET_TIME_UNIT_FOREVER_REL);
340 }
341 return ret;
342}
343
344
345/**
346 * Schedule transmission of the next message from our queue.
347 *
348 * @param h identity provider handle
349 */
350static void
351transmit_next (struct GNUNET_IDENTITY_PROVIDER_Handle *h)
352{
353 struct GNUNET_IDENTITY_PROVIDER_Operation *op = h->op_head;
354
355 GNUNET_assert (NULL == h->th);
356 if (NULL == op)
357 return;
358 if (NULL == h->client)
359 return;
360 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
361 ntohs (op->msg->size),
362 GNUNET_TIME_UNIT_FOREVER_REL,
363 GNUNET_NO,
364 &send_next_message,
365 h);
366}
367
368
369/**
370 * Try again to connect to the service.
371 *
372 * @param cls handle to the identity provider service.
373 * @param tc scheduler context
374 */
375static void
376reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
377{
378 struct GNUNET_IDENTITY_Handle *h = cls;
379 struct GNUNET_IDENTITY_Operation *op;
380 struct GNUNET_MessageHeader msg;
381
382 h->reconnect_task = NULL;
383 LOG (GNUNET_ERROR_TYPE_DEBUG,
384 "Connecting to identity provider service.\n");
385 GNUNET_assert (NULL == h->client);
386 h->client = GNUNET_CLIENT_connect ("identity-provider", h->cfg);
387 GNUNET_assert (NULL != h->client);
388 if ( (NULL == h->op_head) ||
389 (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_START != ntohs (h->op_head->msg->type)) )
390 {
391 op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Operation) +
392 sizeof (struct GNUNET_MessageHeader));
393 op->h = h;
394 op->msg = (const struct GNUNET_MessageHeader *) &op[1];
395 msg.size = htons (sizeof (msg));
396 msg.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_START);
397 memcpy (&op[1], &msg, sizeof (msg));
398 GNUNET_CONTAINER_DLL_insert (h->op_head,
399 h->op_tail,
400 op);
401 }
402 transmit_next (h);
403 GNUNET_assert (NULL != h->th);
404}
405
406
407/**
408 * Connect to the identity provider service.
409 *
410 * @param cfg the configuration to use
411 * @return handle to use
412 */
413struct GNUNET_IDENTITY_PROVIDER_Handle *
414GNUNET_IDENTITY_PROVIDER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
415{
416 struct GNUNET_IDENTITY_PROVIDER_Handle *h;
417
418 h = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Handle);
419 h->cfg = cfg;
420 h->cb = cb;
421 h->cb_cls = cb_cls;
422 h->egos = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_YES);
423 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
424 h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, h);
425 return h;
426}
427
428
429/**
430 * Issue an identity token
431 *
432 * @param id identity service to query
433 * @param service_name for which service is an identity wanted
434 * @param cb function to call with the result (will only be called once)
435 * @param cb_cls closure for @a cb
436 * @return handle to abort the operation
437 */
438struct GNUNET_IDENTITY_PROVIDER_Operation *
439GNUNET_IDENTITY_PROVIDER_issue_token (struct GNUNET_IDENTITY_PROVIDER_Handle *id,
440 const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss_key,
441 const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
442 const char* scopes,
443 const struct GNUNET_TIME_Absolute exp,
444 GNUNET_IDENTITY_PROVIDER_IssueCallback cb,
445 void *cb_cls)
446{
447 struct GNUNET_IDENTITY_PROVIDER_Operation *op;
448 struct GNUNET_IDENTITY_PROVIDER_IssueMessage *im;
449 size_t slen;
450
451 slen = strlen (scopes) + 1;
452 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage))
453 {
454 GNUNET_break (0);
455 return NULL;
456 }
457 op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Operation) +
458 sizeof (struct GNUNET_IDENTITY_IssueMessage) +
459 slen);
460 op->h = id;
461 op->cb = cb;
462 op->cls = cb_cls;
463 im = (struct GNUNET_IDENTITY_GetDefaultMessage *) &op[1];
464 im->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE);
465 im->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage) +
466 slen);
467 im->iss_key = *iss_key;
468 im->aud_key = *aud_ley;
469 im->exp = exp.abs_value_ul;
470 memcpy (&im[1], scopes, slen);
471 op->msg = &im->header;
472 GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
473 id->op_tail,
474 op);
475 if (NULL == id->th)
476 transmit_next (id);
477 return op;
478}
479
480
481/**
482 * Exchange a token ticket for a token
483 *
484 * @param id identity provider service
485 * @param ticket ticket to exchange
486 * @param cont function to call once the operation finished
487 * @param cont_cls closure for @a cont
488 * @return handle to abort the operation
489 */
490struct GNUNET_IDENTITY_PROVIDER_Operation *
491GNUNET_IDENTITY_PROVIDER_exchange_ticket (struct GNUNET_IDENTITY_Handle *id,
492 const char *ticket,
493 GNUNET_IDENTITY_PROVIDER_ExchangeCallback cont,
494 void *cont_cls)
495{
496 struct GNUNET_IDENTITY_PROVIDER_Operation *op;
497 struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *em;
498 size_t slen;
499
500 slen = strlen (ticket) + 1;
501 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_ExchangeMessage))
502 {
503 GNUNET_break (0);
504 return NULL;
505 }
506 op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Operation) +
507 sizeof (struct GNUNET_IDENTITY_ExchangeMessage) +
508 slen);
509 op->h = id;
510 op->cont = cont;
511 op->cls = cont_cls;
512 em = (struct GNUNET_IDENTITY_ExchangeMessage *) &op[1];
513 em->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE);
514 em->header.size = htons (sizeof (struct GNUNET_IDENTITY_ExchangeMessage) +
515 slen);
516 memcpy (&em[1], ticket, slen);
517 op->msg = &em->header;
518 GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
519 id->op_tail,
520 op);
521 if (NULL == id->th)
522 transmit_next (id);
523 return op;
524}
525
526
527/**
528 * Cancel an operation. Note that the operation MAY still
529 * be executed; this merely cancels the continuation; if the request
530 * was already transmitted, the service may still choose to complete
531 * the operation.
532 *
533 * @param op operation to cancel
534 */
535void
536GNUNET_IDENTITY_PROVIDER_cancel (struct GNUNET_IDENTITY_PROVIDER_Operation *op)
537{
538 struct GNUNET_IDENTITY_Handle *h = op->h;
539
540 if ( (h->op_head != op) ||
541 (NULL == h->client) )
542 {
543 /* request not active, can simply remove */
544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
545 "Client aborted non-head operation, simply removing it\n");
546 GNUNET_CONTAINER_DLL_remove (h->op_head,
547 h->op_tail,
548 op);
549 GNUNET_free (op);
550 return;
551 }
552 if (NULL != h->th)
553 {
554 /* request active but not yet with service, can still abort */
555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
556 "Client aborted head operation prior to transmission, aborting it\n");
557 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
558 h->th = NULL;
559 GNUNET_CONTAINER_DLL_remove (h->op_head,
560 h->op_tail,
561 op);
562 GNUNET_free (op);
563 transmit_next (h);
564 return;
565 }
566 /* request active with service, simply ensure continuations are not called */
567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
568 "Client aborted active request, NULLing continuation\n");
569 op->ex_cb = NULL;
570 op->iss_cb = NULL;
571}
572
573
574/**
575 * Disconnect from service
576 *
577 * @param h handle to destroy
578 */
579void
580GNUNET_IDENTITY_PROVIDER_disconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h)
581{
582 struct GNUNET_IDENTITY_PROVIDER_Operation *op;
583
584 GNUNET_assert (NULL != h);
585 if (h->reconnect_task != NULL)
586 {
587 GNUNET_SCHEDULER_cancel (h->reconnect_task);
588 h->reconnect_task = NULL;
589 }
590 if (NULL != h->th)
591 {
592 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
593 h->th = NULL;
594 }
595 while (NULL != (op = h->op_head))
596 {
597 GNUNET_break (NULL == op->cont);
598 GNUNET_CONTAINER_DLL_remove (h->op_head,
599 h->op_tail,
600 op);
601 GNUNET_free (op);
602 }
603 if (NULL != h->client)
604 {
605 GNUNET_CLIENT_disconnect (h->client);
606 h->client = NULL;
607 }
608 GNUNET_free (h);
609}
610
611/* end of identity_provider_api.c */