Migratd simaka_crypto to INIT/METHOD macros
[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 <utils/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 METHOD(simaka_manager_t, add_card, void,
56 private_simaka_manager_t *this, simaka_card_t *card)
57 {
58 this->lock->write_lock(this->lock);
59 this->cards->insert_last(this->cards, card);
60 this->lock->unlock(this->lock);
61 }
62
63 METHOD(simaka_manager_t, remove_card, void,
64 private_simaka_manager_t *this, simaka_card_t *card)
65 {
66 this->lock->write_lock(this->lock);
67 this->cards->remove(this->cards, card, NULL);
68 this->lock->unlock(this->lock);
69 }
70
71 METHOD(simaka_manager_t, card_get_triplet, bool,
72 private_simaka_manager_t *this, identification_t *id,
73 char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN])
74 {
75 enumerator_t *enumerator;
76 simaka_card_t *card;
77 int tried = 0;
78
79 this->lock->read_lock(this->lock);
80 enumerator = this->cards->create_enumerator(this->cards);
81 while (enumerator->enumerate(enumerator, &card))
82 {
83 if (card->get_triplet(card, id, rand, sres, kc))
84 {
85 enumerator->destroy(enumerator);
86 this->lock->unlock(this->lock);
87 return TRUE;
88 }
89 tried++;
90 }
91 enumerator->destroy(enumerator);
92 this->lock->unlock(this->lock);
93 DBG1(DBG_LIB, "tried %d SIM cards, but none has triplets for '%Y'",
94 tried, id);
95 return FALSE;
96 }
97
98 METHOD(simaka_manager_t, card_get_quintuplet, status_t,
99 private_simaka_manager_t *this, identification_t *id, char rand[AKA_RAND_LEN],
100 char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN], char ik[AKA_IK_LEN],
101 char res[AKA_RES_MAX], int *res_len)
102 {
103 enumerator_t *enumerator;
104 simaka_card_t *card;
105 status_t status = NOT_FOUND;
106 int tried = 0;
107
108 this->lock->read_lock(this->lock);
109 enumerator = this->cards->create_enumerator(this->cards);
110 while (enumerator->enumerate(enumerator, &card))
111 {
112 status = card->get_quintuplet(card, id, rand, autn, ck, ik, res, res_len);
113 switch (status)
114 { /* try next on error, but not on INVALID_STATE */
115 case SUCCESS:
116 case INVALID_STATE:
117 enumerator->destroy(enumerator);
118 this->lock->unlock(this->lock);
119 return status;
120 case NOT_SUPPORTED:
121 case FAILED:
122 default:
123 tried++;
124 continue;
125 }
126 }
127 enumerator->destroy(enumerator);
128 this->lock->unlock(this->lock);
129 DBG1(DBG_LIB, "tried %d SIM cards, but none has quintuplets for '%Y'",
130 tried, id);
131 return status;
132 }
133
134 METHOD(simaka_manager_t, card_resync, bool,
135 private_simaka_manager_t *this, identification_t *id,
136 char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
137 {
138 enumerator_t *enumerator;
139 simaka_card_t *card;
140
141 this->lock->read_lock(this->lock);
142 enumerator = this->cards->create_enumerator(this->cards);
143 while (enumerator->enumerate(enumerator, &card))
144 {
145 if (card->resync(card, id, rand, auts))
146 {
147 enumerator->destroy(enumerator);
148 this->lock->unlock(this->lock);
149 return TRUE;
150 }
151 }
152 enumerator->destroy(enumerator);
153 this->lock->unlock(this->lock);
154 return FALSE;
155 }
156
157 METHOD(simaka_manager_t, card_set_pseudonym, void,
158 private_simaka_manager_t *this, identification_t *id,
159 identification_t *pseudonym)
160 {
161 enumerator_t *enumerator;
162 simaka_card_t *card;
163
164 DBG1(DBG_LIB, "storing pseudonym '%Y' for '%Y'", pseudonym, id);
165
166 this->lock->read_lock(this->lock);
167 enumerator = this->cards->create_enumerator(this->cards);
168 while (enumerator->enumerate(enumerator, &card))
169 {
170 card->set_pseudonym(card, id, pseudonym);
171 }
172 enumerator->destroy(enumerator);
173 this->lock->unlock(this->lock);
174 }
175
176 METHOD(simaka_manager_t, card_get_pseudonym, identification_t*,
177 private_simaka_manager_t *this, identification_t *id)
178 {
179 enumerator_t *enumerator;
180 simaka_card_t *card;
181 identification_t *pseudonym = NULL;
182
183 this->lock->read_lock(this->lock);
184 enumerator = this->cards->create_enumerator(this->cards);
185 while (enumerator->enumerate(enumerator, &card))
186 {
187 pseudonym = card->get_pseudonym(card, id);
188 if (pseudonym)
189 {
190 DBG1(DBG_LIB, "using stored pseudonym identity '%Y' "
191 "instead of '%Y'", pseudonym, id);
192 break;
193 }
194 }
195 enumerator->destroy(enumerator);
196 this->lock->unlock(this->lock);
197 return pseudonym;
198 }
199
200 METHOD(simaka_manager_t, card_set_reauth, void,
201 private_simaka_manager_t *this, identification_t *id, identification_t *next,
202 char mk[HASH_SIZE_SHA1], u_int16_t counter)
203 {
204 enumerator_t *enumerator;
205 simaka_card_t *card;
206
207 DBG1(DBG_LIB, "storing next reauthentication identity '%Y' for '%Y'",
208 next, id);
209
210 this->lock->read_lock(this->lock);
211 enumerator = this->cards->create_enumerator(this->cards);
212 while (enumerator->enumerate(enumerator, &card))
213 {
214 card->set_reauth(card, id, next, mk, counter);
215 }
216 enumerator->destroy(enumerator);
217 this->lock->unlock(this->lock);
218 }
219
220 METHOD(simaka_manager_t, card_get_reauth, identification_t*,
221 private_simaka_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1],
222 u_int16_t *counter)
223 {
224 enumerator_t *enumerator;
225 simaka_card_t *card;
226 identification_t *reauth = NULL;
227
228 this->lock->read_lock(this->lock);
229 enumerator = this->cards->create_enumerator(this->cards);
230 while (enumerator->enumerate(enumerator, &card))
231 {
232 reauth = card->get_reauth(card, id, mk, counter);
233 if (reauth)
234 {
235 DBG1(DBG_LIB, "using stored reauthentication identity '%Y' "
236 "instead of '%Y'", reauth, id);
237 break;
238 }
239 }
240 enumerator->destroy(enumerator);
241 this->lock->unlock(this->lock);
242 return reauth;
243 }
244
245 METHOD(simaka_manager_t, add_provider, void,
246 private_simaka_manager_t *this, simaka_provider_t *provider)
247 {
248 this->lock->write_lock(this->lock);
249 this->providers->insert_last(this->providers, provider);
250 this->lock->unlock(this->lock);
251 }
252
253 METHOD(simaka_manager_t, remove_provider, void,
254 private_simaka_manager_t *this, simaka_provider_t *provider)
255 {
256 this->lock->write_lock(this->lock);
257 this->providers->remove(this->providers, provider, NULL);
258 this->lock->unlock(this->lock);
259 }
260
261 METHOD(simaka_manager_t, provider_get_triplet, bool,
262 private_simaka_manager_t *this, identification_t *id,
263 char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN])
264 {
265 enumerator_t *enumerator;
266 simaka_provider_t *provider;
267 int tried = 0;
268
269 this->lock->read_lock(this->lock);
270 enumerator = this->providers->create_enumerator(this->providers);
271 while (enumerator->enumerate(enumerator, &provider))
272 {
273 if (provider->get_triplet(provider, id, rand, sres, kc))
274 {
275 enumerator->destroy(enumerator);
276 this->lock->unlock(this->lock);
277 return TRUE;
278 }
279 tried++;
280 }
281 enumerator->destroy(enumerator);
282 this->lock->unlock(this->lock);
283 DBG1(DBG_LIB, "tried %d SIM providers, but none had a triplet for '%Y'",
284 tried, id);
285 return FALSE;
286 }
287
288 METHOD(simaka_manager_t, provider_get_quintuplet, bool,
289 private_simaka_manager_t *this, identification_t *id,
290 char rand[AKA_RAND_LEN], char xres[AKA_RES_MAX], int *xres_len,
291 char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN])
292 {
293 enumerator_t *enumerator;
294 simaka_provider_t *provider;
295 int tried = 0;
296
297 this->lock->read_lock(this->lock);
298 enumerator = this->providers->create_enumerator(this->providers);
299 while (enumerator->enumerate(enumerator, &provider))
300 {
301 if (provider->get_quintuplet(provider, id, rand, xres, xres_len,
302 ck, ik, autn))
303 {
304 enumerator->destroy(enumerator);
305 this->lock->unlock(this->lock);
306 return TRUE;
307 }
308 }
309 enumerator->destroy(enumerator);
310 this->lock->unlock(this->lock);
311 DBG1(DBG_LIB, "tried %d SIM providers, but none had a quintuplet for '%Y'",
312 tried, id);
313 return FALSE;
314 }
315
316 METHOD(simaka_manager_t, provider_resync, bool,
317 private_simaka_manager_t *this, identification_t *id,
318 char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
319 {
320 enumerator_t *enumerator;
321 simaka_provider_t *provider;
322
323 this->lock->read_lock(this->lock);
324 enumerator = this->providers->create_enumerator(this->providers);
325 while (enumerator->enumerate(enumerator, &provider))
326 {
327 if (provider->resync(provider, id, rand, auts))
328 {
329 enumerator->destroy(enumerator);
330 this->lock->unlock(this->lock);
331 return TRUE;
332 }
333 }
334 enumerator->destroy(enumerator);
335 this->lock->unlock(this->lock);
336 return FALSE;
337 }
338
339 METHOD(simaka_manager_t, provider_is_pseudonym, identification_t*,
340 private_simaka_manager_t *this, identification_t *id)
341 {
342 enumerator_t *enumerator;
343 simaka_provider_t *provider;
344 identification_t *permanent = NULL;
345
346 this->lock->read_lock(this->lock);
347 enumerator = this->providers->create_enumerator(this->providers);
348 while (enumerator->enumerate(enumerator, &provider))
349 {
350 permanent = provider->is_pseudonym(provider, id);
351 if (permanent)
352 {
353 DBG1(DBG_LIB, "received pseudonym identity '%Y' "
354 "mapping to '%Y'", id, permanent);
355 break;
356 }
357 }
358 enumerator->destroy(enumerator);
359 this->lock->unlock(this->lock);
360 return permanent;
361 }
362
363 METHOD(simaka_manager_t, provider_gen_pseudonym, identification_t*,
364 private_simaka_manager_t *this, identification_t *id)
365 {
366 enumerator_t *enumerator;
367 simaka_provider_t *provider;
368 identification_t *pseudonym = NULL;
369
370 this->lock->read_lock(this->lock);
371 enumerator = this->providers->create_enumerator(this->providers);
372 while (enumerator->enumerate(enumerator, &provider))
373 {
374 pseudonym = provider->gen_pseudonym(provider, id);
375 if (pseudonym)
376 {
377 DBG1(DBG_LIB, "proposing new pseudonym '%Y'", pseudonym);
378 break;
379 }
380 }
381 enumerator->destroy(enumerator);
382 this->lock->unlock(this->lock);
383 return pseudonym;
384 }
385
386 METHOD(simaka_manager_t, provider_is_reauth, identification_t*,
387 private_simaka_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1],
388 u_int16_t *counter)
389 {
390 enumerator_t *enumerator;
391 simaka_provider_t *provider;
392 identification_t *permanent = NULL;
393
394 this->lock->read_lock(this->lock);
395 enumerator = this->providers->create_enumerator(this->providers);
396 while (enumerator->enumerate(enumerator, &provider))
397 {
398 permanent = provider->is_reauth(provider, id, mk, counter);
399 if (permanent)
400 {
401 DBG1(DBG_LIB, "received reauthentication identity '%Y' "
402 "mapping to '%Y'", id, permanent);
403 break;
404 }
405 }
406 enumerator->destroy(enumerator);
407 this->lock->unlock(this->lock);
408 return permanent;
409 }
410
411 METHOD(simaka_manager_t, provider_gen_reauth, identification_t*,
412 private_simaka_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1])
413 {
414 enumerator_t *enumerator;
415 simaka_provider_t *provider;
416 identification_t *reauth = NULL;
417
418 this->lock->read_lock(this->lock);
419 enumerator = this->providers->create_enumerator(this->providers);
420 while (enumerator->enumerate(enumerator, &provider))
421 {
422 reauth = provider->gen_reauth(provider, id, mk);
423 if (reauth)
424 {
425 DBG1(DBG_LIB, "proposing new reauthentication identity '%Y'", reauth);
426 break;
427 }
428 }
429 enumerator->destroy(enumerator);
430 this->lock->unlock(this->lock);
431 return reauth;
432 }
433
434 METHOD(simaka_manager_t, add_hooks, void,
435 private_simaka_manager_t *this, simaka_hooks_t *hooks)
436 {
437 this->lock->write_lock(this->lock);
438 this->hooks->insert_last(this->hooks, hooks);
439 this->lock->unlock(this->lock);
440 }
441
442 METHOD(simaka_manager_t, remove_hooks, void,
443 private_simaka_manager_t *this, simaka_hooks_t *hooks)
444 {
445 this->lock->write_lock(this->lock);
446 this->hooks->remove(this->hooks, hooks, NULL);
447 this->lock->unlock(this->lock);
448 }
449
450 METHOD(simaka_manager_t, message_hook, void,
451 private_simaka_manager_t *this, simaka_message_t *message,
452 bool inbound, bool decrypted)
453 {
454 enumerator_t *enumerator;
455 simaka_hooks_t *hooks;
456
457 this->lock->read_lock(this->lock);
458 enumerator = this->hooks->create_enumerator(this->hooks);
459 while (enumerator->enumerate(enumerator, &hooks))
460 {
461 hooks->message(hooks, message, inbound, decrypted);
462 }
463 enumerator->destroy(enumerator);
464 this->lock->unlock(this->lock);
465 }
466
467 METHOD(simaka_manager_t, key_hook, void,
468 private_simaka_manager_t *this, chunk_t k_encr, chunk_t k_auth)
469 {
470 enumerator_t *enumerator;
471 simaka_hooks_t *hooks;
472
473 this->lock->read_lock(this->lock);
474 enumerator = this->hooks->create_enumerator(this->hooks);
475 while (enumerator->enumerate(enumerator, &hooks))
476 {
477 hooks->keys(hooks, k_encr, k_auth);
478 }
479 enumerator->destroy(enumerator);
480 this->lock->unlock(this->lock);
481 }
482
483 METHOD(simaka_manager_t, destroy, void,
484 private_simaka_manager_t *this)
485 {
486 this->cards->destroy(this->cards);
487 this->providers->destroy(this->providers);
488 this->hooks->destroy(this->hooks);
489 this->lock->destroy(this->lock);
490 free(this);
491 }
492
493 /**
494 * See header
495 */
496 simaka_manager_t *simaka_manager_create()
497 {
498 private_simaka_manager_t *this;
499
500 INIT(this,
501 .public = {
502 .add_card = _add_card,
503 .remove_card = _remove_card,
504 .card_get_triplet = _card_get_triplet,
505 .card_get_quintuplet = _card_get_quintuplet,
506 .card_resync = _card_resync,
507 .card_set_pseudonym = _card_set_pseudonym,
508 .card_get_pseudonym = _card_get_pseudonym,
509 .card_set_reauth = _card_set_reauth,
510 .card_get_reauth = _card_get_reauth,
511 .add_provider = _add_provider,
512 .remove_provider = _remove_provider,
513 .provider_get_triplet = _provider_get_triplet,
514 .provider_get_quintuplet = _provider_get_quintuplet,
515 .provider_resync = _provider_resync,
516 .provider_is_pseudonym = _provider_is_pseudonym,
517 .provider_gen_pseudonym = _provider_gen_pseudonym,
518 .provider_is_reauth = _provider_is_reauth,
519 .provider_gen_reauth = _provider_gen_reauth,
520 .add_hooks = _add_hooks,
521 .remove_hooks = _remove_hooks,
522 .message_hook = _message_hook,
523 .key_hook = _key_hook,
524 .destroy = _destroy,
525 },
526 .cards = linked_list_create(),
527 .providers = linked_list_create(),
528 .hooks = linked_list_create(),
529 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
530 );
531
532 return &this->public;
533 }