Moved data structures to new collections subfolder
[strongswan.git] / src / libsimaka / simaka_manager.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "simaka_manager.h"
17
18 #include <debug.h>
19 #include <collections/linked_list.h>
20 #include <threading/rwlock.h>
21
22 typedef struct private_simaka_manager_t private_simaka_manager_t;
23
24 /**
25 * Private data of an simaka_manager_t object.
26 */
27 struct private_simaka_manager_t {
28
29 /**
30 * Public simaka_manager_t interface.
31 */
32 simaka_manager_t public;
33
34 /**
35 * list of added cards
36 */
37 linked_list_t *cards;
38
39 /**
40 * list of added provider
41 */
42 linked_list_t *providers;
43
44 /**
45 * list of added hooks
46 */
47 linked_list_t *hooks;
48
49 /**
50 * lock for lists above
51 */
52 rwlock_t *lock;
53 };
54
55 /**
56 * Described in header.
57 */
58 void libsimaka_init(void)
59 {
60 /* empty */
61 }
62
63 METHOD(simaka_manager_t, add_card, void,
64 private_simaka_manager_t *this, simaka_card_t *card)
65 {
66 this->lock->write_lock(this->lock);
67 this->cards->insert_last(this->cards, card);
68 this->lock->unlock(this->lock);
69 }
70
71 METHOD(simaka_manager_t, remove_card, void,
72 private_simaka_manager_t *this, simaka_card_t *card)
73 {
74 this->lock->write_lock(this->lock);
75 this->cards->remove(this->cards, card, NULL);
76 this->lock->unlock(this->lock);
77 }
78
79 METHOD(simaka_manager_t, card_get_triplet, bool,
80 private_simaka_manager_t *this, identification_t *id,
81 char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN])
82 {
83 enumerator_t *enumerator;
84 simaka_card_t *card;
85 int tried = 0;
86
87 this->lock->read_lock(this->lock);
88 enumerator = this->cards->create_enumerator(this->cards);
89 while (enumerator->enumerate(enumerator, &card))
90 {
91 if (card->get_triplet(card, id, rand, sres, kc))
92 {
93 enumerator->destroy(enumerator);
94 this->lock->unlock(this->lock);
95 return TRUE;
96 }
97 tried++;
98 }
99 enumerator->destroy(enumerator);
100 this->lock->unlock(this->lock);
101 DBG1(DBG_LIB, "tried %d SIM cards, but none has triplets for '%Y'",
102 tried, id);
103 return FALSE;
104 }
105
106 METHOD(simaka_manager_t, card_get_quintuplet, status_t,
107 private_simaka_manager_t *this, identification_t *id, char rand[AKA_RAND_LEN],
108 char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN], char ik[AKA_IK_LEN],
109 char res[AKA_RES_MAX], int *res_len)
110 {
111 enumerator_t *enumerator;
112 simaka_card_t *card;
113 status_t status = NOT_FOUND;
114 int tried = 0;
115
116 this->lock->read_lock(this->lock);
117 enumerator = this->cards->create_enumerator(this->cards);
118 while (enumerator->enumerate(enumerator, &card))
119 {
120 status = card->get_quintuplet(card, id, rand, autn, ck, ik, res, res_len);
121 switch (status)
122 { /* try next on error, but not on INVALID_STATE */
123 case SUCCESS:
124 case INVALID_STATE:
125 enumerator->destroy(enumerator);
126 this->lock->unlock(this->lock);
127 return status;
128 case NOT_SUPPORTED:
129 case FAILED:
130 default:
131 tried++;
132 continue;
133 }
134 }
135 enumerator->destroy(enumerator);
136 this->lock->unlock(this->lock);
137 DBG1(DBG_LIB, "tried %d SIM cards, but none has quintuplets for '%Y'",
138 tried, id);
139 return status;
140 }
141
142 METHOD(simaka_manager_t, card_resync, bool,
143 private_simaka_manager_t *this, identification_t *id,
144 char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
145 {
146 enumerator_t *enumerator;
147 simaka_card_t *card;
148
149 this->lock->read_lock(this->lock);
150 enumerator = this->cards->create_enumerator(this->cards);
151 while (enumerator->enumerate(enumerator, &card))
152 {
153 if (card->resync(card, id, rand, auts))
154 {
155 enumerator->destroy(enumerator);
156 this->lock->unlock(this->lock);
157 return TRUE;
158 }
159 }
160 enumerator->destroy(enumerator);
161 this->lock->unlock(this->lock);
162 return FALSE;
163 }
164
165 METHOD(simaka_manager_t, card_set_pseudonym, void,
166 private_simaka_manager_t *this, identification_t *id,
167 identification_t *pseudonym)
168 {
169 enumerator_t *enumerator;
170 simaka_card_t *card;
171
172 DBG1(DBG_LIB, "storing pseudonym '%Y' for '%Y'", pseudonym, id);
173
174 this->lock->read_lock(this->lock);
175 enumerator = this->cards->create_enumerator(this->cards);
176 while (enumerator->enumerate(enumerator, &card))
177 {
178 card->set_pseudonym(card, id, pseudonym);
179 }
180 enumerator->destroy(enumerator);
181 this->lock->unlock(this->lock);
182 }
183
184 METHOD(simaka_manager_t, card_get_pseudonym, identification_t*,
185 private_simaka_manager_t *this, identification_t *id)
186 {
187 enumerator_t *enumerator;
188 simaka_card_t *card;
189 identification_t *pseudonym = NULL;
190
191 this->lock->read_lock(this->lock);
192 enumerator = this->cards->create_enumerator(this->cards);
193 while (enumerator->enumerate(enumerator, &card))
194 {
195 pseudonym = card->get_pseudonym(card, id);
196 if (pseudonym)
197 {
198 DBG1(DBG_LIB, "using stored pseudonym identity '%Y' "
199 "instead of '%Y'", pseudonym, id);
200 break;
201 }
202 }
203 enumerator->destroy(enumerator);
204 this->lock->unlock(this->lock);
205 return pseudonym;
206 }
207
208 METHOD(simaka_manager_t, card_set_reauth, void,
209 private_simaka_manager_t *this, identification_t *id, identification_t *next,
210 char mk[HASH_SIZE_SHA1], u_int16_t counter)
211 {
212 enumerator_t *enumerator;
213 simaka_card_t *card;
214
215 DBG1(DBG_LIB, "storing next reauthentication identity '%Y' for '%Y'",
216 next, id);
217
218 this->lock->read_lock(this->lock);
219 enumerator = this->cards->create_enumerator(this->cards);
220 while (enumerator->enumerate(enumerator, &card))
221 {
222 card->set_reauth(card, id, next, mk, counter);
223 }
224 enumerator->destroy(enumerator);
225 this->lock->unlock(this->lock);
226 }
227
228 METHOD(simaka_manager_t, card_get_reauth, identification_t*,
229 private_simaka_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1],
230 u_int16_t *counter)
231 {
232 enumerator_t *enumerator;
233 simaka_card_t *card;
234 identification_t *reauth = NULL;
235
236 this->lock->read_lock(this->lock);
237 enumerator = this->cards->create_enumerator(this->cards);
238 while (enumerator->enumerate(enumerator, &card))
239 {
240 reauth = card->get_reauth(card, id, mk, counter);
241 if (reauth)
242 {
243 DBG1(DBG_LIB, "using stored reauthentication identity '%Y' "
244 "instead of '%Y'", reauth, id);
245 break;
246 }
247 }
248 enumerator->destroy(enumerator);
249 this->lock->unlock(this->lock);
250 return reauth;
251 }
252
253 METHOD(simaka_manager_t, add_provider, void,
254 private_simaka_manager_t *this, simaka_provider_t *provider)
255 {
256 this->lock->write_lock(this->lock);
257 this->providers->insert_last(this->providers, provider);
258 this->lock->unlock(this->lock);
259 }
260
261 METHOD(simaka_manager_t, remove_provider, void,
262 private_simaka_manager_t *this, simaka_provider_t *provider)
263 {
264 this->lock->write_lock(this->lock);
265 this->providers->remove(this->providers, provider, NULL);
266 this->lock->unlock(this->lock);
267 }
268
269 METHOD(simaka_manager_t, provider_get_triplet, bool,
270 private_simaka_manager_t *this, identification_t *id,
271 char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN])
272 {
273 enumerator_t *enumerator;
274 simaka_provider_t *provider;
275 int tried = 0;
276
277 this->lock->read_lock(this->lock);
278 enumerator = this->providers->create_enumerator(this->providers);
279 while (enumerator->enumerate(enumerator, &provider))
280 {
281 if (provider->get_triplet(provider, id, rand, sres, kc))
282 {
283 enumerator->destroy(enumerator);
284 this->lock->unlock(this->lock);
285 return TRUE;
286 }
287 tried++;
288 }
289 enumerator->destroy(enumerator);
290 this->lock->unlock(this->lock);
291 DBG1(DBG_LIB, "tried %d SIM providers, but none had a triplet for '%Y'",
292 tried, id);
293 return FALSE;
294 }
295
296 METHOD(simaka_manager_t, provider_get_quintuplet, bool,
297 private_simaka_manager_t *this, identification_t *id,
298 char rand[AKA_RAND_LEN], char xres[AKA_RES_MAX], int *xres_len,
299 char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN])
300 {
301 enumerator_t *enumerator;
302 simaka_provider_t *provider;
303 int tried = 0;
304
305 this->lock->read_lock(this->lock);
306 enumerator = this->providers->create_enumerator(this->providers);
307 while (enumerator->enumerate(enumerator, &provider))
308 {
309 if (provider->get_quintuplet(provider, id, rand, xres, xres_len,
310 ck, ik, autn))
311 {
312 enumerator->destroy(enumerator);
313 this->lock->unlock(this->lock);
314 return TRUE;
315 }
316 }
317 enumerator->destroy(enumerator);
318 this->lock->unlock(this->lock);
319 DBG1(DBG_LIB, "tried %d SIM providers, but none had a quintuplet for '%Y'",
320 tried, id);
321 return FALSE;
322 }
323
324 METHOD(simaka_manager_t, provider_resync, bool,
325 private_simaka_manager_t *this, identification_t *id,
326 char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
327 {
328 enumerator_t *enumerator;
329 simaka_provider_t *provider;
330
331 this->lock->read_lock(this->lock);
332 enumerator = this->providers->create_enumerator(this->providers);
333 while (enumerator->enumerate(enumerator, &provider))
334 {
335 if (provider->resync(provider, id, rand, auts))
336 {
337 enumerator->destroy(enumerator);
338 this->lock->unlock(this->lock);
339 return TRUE;
340 }
341 }
342 enumerator->destroy(enumerator);
343 this->lock->unlock(this->lock);
344 return FALSE;
345 }
346
347 METHOD(simaka_manager_t, provider_is_pseudonym, identification_t*,
348 private_simaka_manager_t *this, identification_t *id)
349 {
350 enumerator_t *enumerator;
351 simaka_provider_t *provider;
352 identification_t *permanent = NULL;
353
354 this->lock->read_lock(this->lock);
355 enumerator = this->providers->create_enumerator(this->providers);
356 while (enumerator->enumerate(enumerator, &provider))
357 {
358 permanent = provider->is_pseudonym(provider, id);
359 if (permanent)
360 {
361 DBG1(DBG_LIB, "received pseudonym identity '%Y' "
362 "mapping to '%Y'", id, permanent);
363 break;
364 }
365 }
366 enumerator->destroy(enumerator);
367 this->lock->unlock(this->lock);
368 return permanent;
369 }
370
371 METHOD(simaka_manager_t, provider_gen_pseudonym, identification_t*,
372 private_simaka_manager_t *this, identification_t *id)
373 {
374 enumerator_t *enumerator;
375 simaka_provider_t *provider;
376 identification_t *pseudonym = NULL;
377
378 this->lock->read_lock(this->lock);
379 enumerator = this->providers->create_enumerator(this->providers);
380 while (enumerator->enumerate(enumerator, &provider))
381 {
382 pseudonym = provider->gen_pseudonym(provider, id);
383 if (pseudonym)
384 {
385 DBG1(DBG_LIB, "proposing new pseudonym '%Y'", pseudonym);
386 break;
387 }
388 }
389 enumerator->destroy(enumerator);
390 this->lock->unlock(this->lock);
391 return pseudonym;
392 }
393
394 METHOD(simaka_manager_t, provider_is_reauth, identification_t*,
395 private_simaka_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1],
396 u_int16_t *counter)
397 {
398 enumerator_t *enumerator;
399 simaka_provider_t *provider;
400 identification_t *permanent = NULL;
401
402 this->lock->read_lock(this->lock);
403 enumerator = this->providers->create_enumerator(this->providers);
404 while (enumerator->enumerate(enumerator, &provider))
405 {
406 permanent = provider->is_reauth(provider, id, mk, counter);
407 if (permanent)
408 {
409 DBG1(DBG_LIB, "received reauthentication identity '%Y' "
410 "mapping to '%Y'", id, permanent);
411 break;
412 }
413 }
414 enumerator->destroy(enumerator);
415 this->lock->unlock(this->lock);
416 return permanent;
417 }
418
419 METHOD(simaka_manager_t, provider_gen_reauth, identification_t*,
420 private_simaka_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1])
421 {
422 enumerator_t *enumerator;
423 simaka_provider_t *provider;
424 identification_t *reauth = NULL;
425
426 this->lock->read_lock(this->lock);
427 enumerator = this->providers->create_enumerator(this->providers);
428 while (enumerator->enumerate(enumerator, &provider))
429 {
430 reauth = provider->gen_reauth(provider, id, mk);
431 if (reauth)
432 {
433 DBG1(DBG_LIB, "proposing new reauthentication identity '%Y'", reauth);
434 break;
435 }
436 }
437 enumerator->destroy(enumerator);
438 this->lock->unlock(this->lock);
439 return reauth;
440 }
441
442 METHOD(simaka_manager_t, add_hooks, void,
443 private_simaka_manager_t *this, simaka_hooks_t *hooks)
444 {
445 this->lock->write_lock(this->lock);
446 this->hooks->insert_last(this->hooks, hooks);
447 this->lock->unlock(this->lock);
448 }
449
450 METHOD(simaka_manager_t, remove_hooks, void,
451 private_simaka_manager_t *this, simaka_hooks_t *hooks)
452 {
453 this->lock->write_lock(this->lock);
454 this->hooks->remove(this->hooks, hooks, NULL);
455 this->lock->unlock(this->lock);
456 }
457
458 METHOD(simaka_manager_t, message_hook, void,
459 private_simaka_manager_t *this, simaka_message_t *message,
460 bool inbound, bool decrypted)
461 {
462 enumerator_t *enumerator;
463 simaka_hooks_t *hooks;
464
465 this->lock->read_lock(this->lock);
466 enumerator = this->hooks->create_enumerator(this->hooks);
467 while (enumerator->enumerate(enumerator, &hooks))
468 {
469 hooks->message(hooks, message, inbound, decrypted);
470 }
471 enumerator->destroy(enumerator);
472 this->lock->unlock(this->lock);
473 }
474
475 METHOD(simaka_manager_t, key_hook, void,
476 private_simaka_manager_t *this, chunk_t k_encr, chunk_t k_auth)
477 {
478 enumerator_t *enumerator;
479 simaka_hooks_t *hooks;
480
481 this->lock->read_lock(this->lock);
482 enumerator = this->hooks->create_enumerator(this->hooks);
483 while (enumerator->enumerate(enumerator, &hooks))
484 {
485 hooks->keys(hooks, k_encr, k_auth);
486 }
487 enumerator->destroy(enumerator);
488 this->lock->unlock(this->lock);
489 }
490
491 METHOD(simaka_manager_t, destroy, void,
492 private_simaka_manager_t *this)
493 {
494 this->cards->destroy(this->cards);
495 this->providers->destroy(this->providers);
496 this->hooks->destroy(this->hooks);
497 this->lock->destroy(this->lock);
498 free(this);
499 }
500
501 /**
502 * See header
503 */
504 simaka_manager_t *simaka_manager_create()
505 {
506 private_simaka_manager_t *this;
507
508 INIT(this,
509 .public = {
510 .add_card = _add_card,
511 .remove_card = _remove_card,
512 .card_get_triplet = _card_get_triplet,
513 .card_get_quintuplet = _card_get_quintuplet,
514 .card_resync = _card_resync,
515 .card_set_pseudonym = _card_set_pseudonym,
516 .card_get_pseudonym = _card_get_pseudonym,
517 .card_set_reauth = _card_set_reauth,
518 .card_get_reauth = _card_get_reauth,
519 .add_provider = _add_provider,
520 .remove_provider = _remove_provider,
521 .provider_get_triplet = _provider_get_triplet,
522 .provider_get_quintuplet = _provider_get_quintuplet,
523 .provider_resync = _provider_resync,
524 .provider_is_pseudonym = _provider_is_pseudonym,
525 .provider_gen_pseudonym = _provider_gen_pseudonym,
526 .provider_is_reauth = _provider_is_reauth,
527 .provider_gen_reauth = _provider_gen_reauth,
528 .add_hooks = _add_hooks,
529 .remove_hooks = _remove_hooks,
530 .message_hook = _message_hook,
531 .key_hook = _key_hook,
532 .destroy = _destroy,
533 },
534 .cards = linked_list_create(),
535 .providers = linked_list_create(),
536 .hooks = linked_list_create(),
537 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
538 );
539
540 return &this->public;
541 }
542
543 /**
544 * (Un-)register a provider to a simaka manager
545 */
546 static bool register_card(char *mgr_name, bool reg, simaka_card_t *card)
547 {
548 simaka_manager_t *mgr;
549
550 if (!card)
551 {
552 return FALSE;
553 }
554 mgr = lib->get(lib, mgr_name);
555 if (mgr)
556 {
557 if (reg)
558 {
559 mgr->add_card(mgr, card);
560 }
561 else
562 {
563 mgr->remove_card(mgr, card);
564 }
565 return TRUE;
566 }
567 return FALSE;
568 }
569
570 /**
571 * (Un-)register a provider to a simaka manager
572 */
573 static bool register_provider(char *mgr_name, bool reg,
574 simaka_provider_t *provider)
575 {
576 simaka_manager_t *mgr;
577
578 if (!provider)
579 {
580 return FALSE;
581 }
582 mgr = lib->get(lib, mgr_name);
583 if (mgr)
584 {
585 if (reg)
586 {
587 mgr->add_provider(mgr, provider);
588 }
589 else
590 {
591 mgr->remove_provider(mgr, provider);
592 }
593 return TRUE;
594 }
595 return FALSE;
596 }
597
598 /**
599 * See header
600 */
601 bool simaka_manager_register(plugin_t *plugin, plugin_feature_t *feature,
602 bool reg, void *data)
603 {
604 simaka_manager_register_cb_t get = (simaka_manager_register_cb_t)data;
605
606 if (feature->type == FEATURE_CUSTOM)
607 {
608 if (streq(feature->arg.custom, "aka-card"))
609 {
610 return register_card("aka-manager", reg, get(plugin));
611 }
612 else if (streq(feature->arg.custom, "aka-provider"))
613 {
614 return register_provider("aka-manager", reg, get(plugin));
615 }
616 else if (streq(feature->arg.custom, "sim-card"))
617 {
618 return register_card("sim-manager", reg, get(plugin));
619 }
620 else if (streq(feature->arg.custom, "sim-provider"))
621 {
622 return register_provider("sim-manager", reg, get(plugin));
623 }
624 }
625 return FALSE;
626 }