Coverage Report

Created: 2026-08-14 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libcharon/bus/bus.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2011-2020 Tobias Brunner
3
 * Copyright (C) 2006 Martin Willi
4
 *
5
 * Copyright (C) secunet Security Networks AG
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published by the
9
 * Free Software Foundation; either version 2 of the License, or (at your
10
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11
 *
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
 * for more details.
16
 */
17
18
#include "bus.h"
19
20
#include <stdint.h>
21
22
#include <threading/thread.h>
23
#include <threading/thread_value.h>
24
#include <threading/mutex.h>
25
#include <threading/rwlock.h>
26
27
/**
28
 * These operations allow us to speed up the log level checks on some platforms.
29
 * In particular if acquiring the read lock is expensive even in the absence of
30
 * any writers.
31
 *
32
 * Note that while holding the read/write lock the read does not have to be
33
 * atomic as the write lock must be held to set the level.
34
 */
35
#ifdef HAVE_GCC_ATOMIC_OPERATIONS
36
37
0
#define skip_level(ptr, level) (__atomic_load_n(ptr, __ATOMIC_RELAXED) < level)
38
0
#define set_level(ptr, val) __atomic_store_n(ptr, val, __ATOMIC_RELAXED)
39
40
#elif defined(HAVE_GCC_SYNC_OPERATIONS)
41
42
#define skip_level(ptr, level) (__sync_fetch_and_add(ptr, 0) < level)
43
#define set_level(ptr, val) __sync_bool_compare_and_swap(ptr, *ptr, val)
44
45
#else
46
47
#define skip_level(ptr, level) FALSE
48
#define set_level(ptr, val) ({ *ptr = val; })
49
50
#endif
51
52
typedef struct private_bus_t private_bus_t;
53
54
/**
55
 * Private data of a bus_t object.
56
 */
57
struct private_bus_t {
58
  /**
59
   * Public part of a bus_t object.
60
   */
61
  bus_t public;
62
63
  /**
64
   * List of registered listeners as entry_t.
65
   */
66
  linked_list_t *listeners;
67
68
  /**
69
   * List of registered loggers for each log group as log_entry_t.
70
   * Loggers are ordered by descending log level.
71
   * The extra list stores all loggers so we can properly unregister them.
72
   */
73
  linked_list_t *loggers[DBG_MAX + 1];
74
75
  /**
76
   * Maximum log level of any registered logger for each log group.
77
   * This allows to check quickly if a log message has to be logged at all.
78
   */
79
  level_t max_level[DBG_MAX + 1];
80
81
  /**
82
   * Same as max level, but for loggers using the vlog() method.
83
   */
84
  level_t max_vlevel[DBG_MAX + 1];
85
86
  /**
87
   * Mutex for the list of listeners, recursively.
88
   */
89
  mutex_t *mutex;
90
91
  /**
92
   * Read-write lock for the list of loggers.
93
   */
94
  rwlock_t *log_lock;
95
96
  /**
97
   * Thread local storage the threads IKE_SA
98
   */
99
  thread_value_t *thread_sa;
100
};
101
102
typedef struct entry_t entry_t;
103
104
/**
105
 * a listener entry
106
 */
107
struct entry_t {
108
109
  /**
110
   * registered listener interface
111
   */
112
  listener_t *listener;
113
114
  /**
115
   * are we currently calling this listener
116
   */
117
  int calling;
118
119
};
120
121
typedef struct log_entry_t log_entry_t;
122
123
/**
124
 * a logger entry
125
 */
126
struct log_entry_t {
127
128
  /**
129
   * registered logger interface
130
   */
131
  logger_t *logger;
132
133
  /**
134
   * registered log levels per group
135
   */
136
  level_t levels[DBG_MAX];
137
138
};
139
140
METHOD(bus_t, add_listener, void,
141
  private_bus_t *this, listener_t *listener)
142
2
{
143
2
  entry_t *entry;
144
145
2
  INIT(entry,
146
2
    .listener = listener,
147
2
  );
148
149
2
  this->mutex->lock(this->mutex);
150
2
  this->listeners->insert_last(this->listeners, entry);
151
2
  this->mutex->unlock(this->mutex);
152
2
}
153
154
METHOD(bus_t, remove_listener, void,
155
  private_bus_t *this, listener_t *listener)
156
0
{
157
0
  enumerator_t *enumerator;
158
0
  entry_t *entry;
159
160
0
  this->mutex->lock(this->mutex);
161
0
  enumerator = this->listeners->create_enumerator(this->listeners);
162
0
  while (enumerator->enumerate(enumerator, &entry))
163
0
  {
164
0
    if (entry->listener == listener)
165
0
    {
166
0
      this->listeners->remove_at(this->listeners, enumerator);
167
0
      free(entry);
168
0
      break;
169
0
    }
170
0
  }
171
0
  enumerator->destroy(enumerator);
172
0
  this->mutex->unlock(this->mutex);
173
0
}
174
175
/**
176
 * Register a logger on the given log group according to the requested level
177
 */
178
static inline void register_logger(private_bus_t *this, debug_t group,
179
                   log_entry_t *entry)
180
0
{
181
0
  enumerator_t *enumerator;
182
0
  linked_list_t *loggers;
183
0
  log_entry_t *current;
184
0
  level_t level;
185
186
0
  loggers = this->loggers[group];
187
0
  level = entry->levels[group];
188
189
0
  enumerator = loggers->create_enumerator(loggers);
190
0
  while (enumerator->enumerate(enumerator, (void**)&current))
191
0
  {
192
0
    if (current->levels[group] <= level)
193
0
    {
194
0
      break;
195
0
    }
196
0
  }
197
0
  loggers->insert_before(loggers, enumerator, entry);
198
0
  enumerator->destroy(enumerator);
199
200
0
  if (entry->logger->log)
201
0
  {
202
0
    set_level(&this->max_level[group], max(this->max_level[group], level));
203
0
  }
204
0
  if (entry->logger->vlog)
205
0
  {
206
0
    set_level(&this->max_vlevel[group],
207
0
          max(this->max_vlevel[group], level));
208
0
  }
209
0
}
210
211
CALLBACK(find_max_levels, bool,
212
  log_entry_t *entry, va_list args)
213
0
{
214
0
  level_t *level, *vlevel;
215
0
  debug_t group;
216
217
0
  VA_ARGS_VGET(args, group, level, vlevel);
218
0
  if (entry->logger->log && *level == LEVEL_SILENT)
219
0
  {
220
0
    *level = entry->levels[group];
221
0
  }
222
0
  if (entry->logger->vlog && *vlevel == LEVEL_SILENT)
223
0
  {
224
0
    *vlevel = entry->levels[group];
225
0
  }
226
0
  return *level > LEVEL_SILENT && *vlevel > LEVEL_SILENT;
227
0
}
228
229
/**
230
 * Unregister a logger from all log groups (destroys the log_entry_t)
231
 */
232
static inline void unregister_logger(private_bus_t *this, logger_t *logger)
233
0
{
234
0
  enumerator_t *enumerator;
235
0
  linked_list_t *loggers;
236
0
  log_entry_t *entry, *found = NULL;
237
0
  debug_t group;
238
239
0
  loggers = this->loggers[DBG_MAX];
240
0
  enumerator = loggers->create_enumerator(loggers);
241
0
  while (enumerator->enumerate(enumerator, &entry))
242
0
  {
243
0
    if (entry->logger == logger)
244
0
    {
245
0
      loggers->remove_at(loggers, enumerator);
246
0
      found = entry;
247
0
      break;
248
0
    }
249
0
  }
250
0
  enumerator->destroy(enumerator);
251
252
0
  if (found)
253
0
  {
254
0
    for (group = 0; group < DBG_MAX; group++)
255
0
    {
256
0
      if (found->levels[group] > LEVEL_SILENT)
257
0
      {
258
0
        level_t level = LEVEL_SILENT, vlevel = LEVEL_SILENT;
259
260
0
        loggers = this->loggers[group];
261
0
        loggers->remove(loggers, found, NULL);
262
0
        loggers->find_first(loggers, find_max_levels, NULL, group,
263
0
                  &level, &vlevel);
264
0
        set_level(&this->max_level[group], level);
265
0
        set_level(&this->max_vlevel[group], vlevel);
266
0
      }
267
0
    }
268
0
    free(found);
269
0
  }
270
0
}
271
272
METHOD(bus_t, add_logger, void,
273
  private_bus_t *this, logger_t *logger)
274
0
{
275
0
  log_entry_t *entry;
276
0
  debug_t group;
277
278
0
  INIT(entry,
279
0
    .logger = logger,
280
0
  );
281
282
0
  this->log_lock->write_lock(this->log_lock);
283
0
  unregister_logger(this, logger);
284
0
  for (group = 0; group < DBG_MAX; group++)
285
0
  {
286
0
    entry->levels[group] = logger->get_level(logger, group);
287
0
    if (entry->levels[group] > LEVEL_SILENT)
288
0
    {
289
0
      register_logger(this, group, entry);
290
0
    }
291
0
  }
292
0
  this->loggers[DBG_MAX]->insert_last(this->loggers[DBG_MAX], entry);
293
0
  this->log_lock->unlock(this->log_lock);
294
0
}
295
296
METHOD(bus_t, remove_logger, void,
297
  private_bus_t *this, logger_t *logger)
298
0
{
299
0
  this->log_lock->write_lock(this->log_lock);
300
0
  unregister_logger(this, logger);
301
0
  this->log_lock->unlock(this->log_lock);
302
0
}
303
304
METHOD(bus_t, set_sa, void,
305
  private_bus_t *this, ike_sa_t *ike_sa)
306
0
{
307
0
  this->thread_sa->set(this->thread_sa, ike_sa);
308
0
}
309
310
METHOD(bus_t, get_sa, ike_sa_t*,
311
  private_bus_t *this)
312
0
{
313
0
  return this->thread_sa->get(this->thread_sa);
314
0
}
315
316
/**
317
 * data associated to a signal, passed to callback
318
 */
319
typedef struct {
320
  /** associated IKE_SA */
321
  ike_sa_t *ike_sa;
322
  /** invoking thread */
323
  long thread;
324
  /** debug group */
325
  debug_t group;
326
  /** debug level */
327
  level_t level;
328
  /** message/fmt */
329
  char *message;
330
  /** argument list if message is a format string for vlog() */
331
  va_list args;
332
} log_data_t;
333
334
CALLBACK(log_cb, void,
335
  log_entry_t *entry, va_list args)
336
0
{
337
0
  log_data_t *data;
338
339
0
  VA_ARGS_VGET(args, data);
340
0
  if (entry->logger->log && entry->levels[data->group] >= data->level)
341
0
  {
342
0
    entry->logger->log(entry->logger, data->group, data->level,
343
0
               data->thread, data->ike_sa, data->message);
344
0
  }
345
0
}
346
347
CALLBACK(vlog_cb, void,
348
  log_entry_t *entry, va_list args)
349
0
{
350
0
  log_data_t *data;
351
352
0
  VA_ARGS_VGET(args, data);
353
0
  if (entry->logger->vlog && entry->levels[data->group] >= data->level)
354
0
  {
355
0
    va_list copy;
356
357
0
    va_copy(copy, data->args);
358
0
    entry->logger->vlog(entry->logger, data->group, data->level,
359
0
              data->thread, data->ike_sa, data->message, copy);
360
0
    va_end(copy);
361
0
  }
362
0
}
363
364
METHOD(bus_t, vlog, void,
365
  private_bus_t *this, debug_t group, level_t level,
366
  char* format, va_list args)
367
0
{
368
0
  linked_list_t *loggers;
369
0
  log_data_t data;
370
371
  /* NOTE: This is not 100% thread-safe and done here only because it is
372
   * performance critical.  We therefore ignore the following two issues for
373
   * this particular case:  1) We might miss some log messages if another
374
   * thread concurrently increases the log level or registers a new logger.
375
   * 2) We might have to acquire the read lock below even if it wouldn't be
376
   * necessary anymore due to another thread concurrently unregistering a
377
   * logger or reducing the level. */
378
0
  if (skip_level(&this->max_level[group], level) &&
379
0
    skip_level(&this->max_vlevel[group], level))
380
0
  {
381
0
    return;
382
0
  }
383
384
0
  this->log_lock->read_lock(this->log_lock);
385
0
  loggers = this->loggers[group];
386
387
0
  if (this->max_level[group] >= level)
388
0
  {
389
0
    char buf[1024];
390
0
    ssize_t len;
391
392
0
    data.ike_sa = this->thread_sa->get(this->thread_sa);
393
0
    data.thread = thread_current_id();
394
0
    data.group = group;
395
0
    data.level = level;
396
0
    data.message = buf;
397
398
0
    va_copy(data.args, args);
399
0
    len = vsnprintf(data.message, sizeof(buf), format, data.args);
400
0
    va_end(data.args);
401
0
    if (len >= sizeof(buf))
402
0
    {
403
0
      len++;
404
0
      data.message = malloc(len);
405
0
      va_copy(data.args, args);
406
0
      len = vsnprintf(data.message, len, format, data.args);
407
0
      va_end(data.args);
408
0
    }
409
0
    if (len > 0)
410
0
    {
411
0
      loggers->invoke_function(loggers, log_cb, &data);
412
0
    }
413
0
    if (data.message != buf)
414
0
    {
415
0
      free(data.message);
416
0
    }
417
0
  }
418
0
  if (this->max_vlevel[group] >= level)
419
0
  {
420
0
    data.ike_sa = this->thread_sa->get(this->thread_sa);
421
0
    data.thread = thread_current_id();
422
0
    data.group = group;
423
0
    data.level = level;
424
0
    data.message = format;
425
426
0
    va_copy(data.args, args);
427
0
    loggers->invoke_function(loggers, vlog_cb, &data);
428
0
    va_end(data.args);
429
0
  }
430
431
0
  this->log_lock->unlock(this->log_lock);
432
0
}
433
434
METHOD(bus_t, log_, void,
435
  private_bus_t *this, debug_t group, level_t level, char* format, ...)
436
0
{
437
0
  va_list args;
438
439
0
  va_start(args, format);
440
0
  vlog(this, group, level, format, args);
441
0
  va_end(args);
442
0
}
443
444
/**
445
 * unregister a listener
446
 */
447
static inline void unregister_listener(private_bus_t *this, entry_t *entry,
448
                     enumerator_t *enumerator)
449
0
{
450
0
  this->listeners->remove_at(this->listeners, enumerator);
451
0
  free(entry);
452
0
}
453
454
METHOD(bus_t, alert, void,
455
  private_bus_t *this, alert_t alert, ...)
456
0
{
457
0
  enumerator_t *enumerator;
458
0
  ike_sa_t *ike_sa;
459
0
  entry_t *entry;
460
0
  va_list args;
461
0
  bool keep;
462
463
0
  ike_sa = this->thread_sa->get(this->thread_sa);
464
465
0
  this->mutex->lock(this->mutex);
466
0
  enumerator = this->listeners->create_enumerator(this->listeners);
467
0
  while (enumerator->enumerate(enumerator, &entry))
468
0
  {
469
0
    if (entry->calling || !entry->listener->alert)
470
0
    {
471
0
      continue;
472
0
    }
473
0
    entry->calling++;
474
0
    va_start(args, alert);
475
0
    keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
476
0
    va_end(args);
477
0
    entry->calling--;
478
0
    if (!keep)
479
0
    {
480
0
      unregister_listener(this, entry, enumerator);
481
0
    }
482
0
  }
483
0
  enumerator->destroy(enumerator);
484
0
  this->mutex->unlock(this->mutex);
485
0
}
486
487
METHOD(bus_t, ike_state_change, void,
488
  private_bus_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
489
0
{
490
0
  enumerator_t *enumerator;
491
0
  entry_t *entry;
492
0
  bool keep;
493
494
0
  this->mutex->lock(this->mutex);
495
0
  enumerator = this->listeners->create_enumerator(this->listeners);
496
0
  while (enumerator->enumerate(enumerator, &entry))
497
0
  {
498
0
    if (entry->calling || !entry->listener->ike_state_change)
499
0
    {
500
0
      continue;
501
0
    }
502
0
    entry->calling++;
503
0
    keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
504
0
    entry->calling--;
505
0
    if (!keep)
506
0
    {
507
0
      unregister_listener(this, entry, enumerator);
508
0
    }
509
0
  }
510
0
  enumerator->destroy(enumerator);
511
0
  this->mutex->unlock(this->mutex);
512
0
}
513
514
METHOD(bus_t, child_state_change, void,
515
  private_bus_t *this, child_sa_t *child_sa, child_sa_state_t state)
516
0
{
517
0
  enumerator_t *enumerator;
518
0
  ike_sa_t *ike_sa;
519
0
  entry_t *entry;
520
0
  bool keep;
521
522
0
  ike_sa = this->thread_sa->get(this->thread_sa);
523
524
0
  this->mutex->lock(this->mutex);
525
0
  enumerator = this->listeners->create_enumerator(this->listeners);
526
0
  while (enumerator->enumerate(enumerator, &entry))
527
0
  {
528
0
    if (entry->calling || !entry->listener->child_state_change)
529
0
    {
530
0
      continue;
531
0
    }
532
0
    entry->calling++;
533
0
    keep = entry->listener->child_state_change(entry->listener, ike_sa,
534
0
                           child_sa, state);
535
0
    entry->calling--;
536
0
    if (!keep)
537
0
    {
538
0
      unregister_listener(this, entry, enumerator);
539
0
    }
540
0
  }
541
0
  enumerator->destroy(enumerator);
542
0
  this->mutex->unlock(this->mutex);
543
0
}
544
545
METHOD(bus_t, message, void,
546
  private_bus_t *this, message_t *message, bool incoming, bool plain)
547
0
{
548
0
  enumerator_t *enumerator;
549
0
  ike_sa_t *ike_sa;
550
0
  entry_t *entry;
551
0
  bool keep;
552
553
0
  ike_sa = this->thread_sa->get(this->thread_sa);
554
555
0
  this->mutex->lock(this->mutex);
556
0
  enumerator = this->listeners->create_enumerator(this->listeners);
557
0
  while (enumerator->enumerate(enumerator, &entry))
558
0
  {
559
0
    if (entry->calling || !entry->listener->message)
560
0
    {
561
0
      continue;
562
0
    }
563
0
    entry->calling++;
564
0
    keep = entry->listener->message(entry->listener, ike_sa,
565
0
                    message, incoming, plain);
566
0
    entry->calling--;
567
0
    if (!keep)
568
0
    {
569
0
      unregister_listener(this, entry, enumerator);
570
0
    }
571
0
  }
572
0
  enumerator->destroy(enumerator);
573
0
  this->mutex->unlock(this->mutex);
574
0
}
575
576
METHOD(bus_t, ike_keys, void,
577
  private_bus_t *this, ike_sa_t *ike_sa, array_t *kes,
578
  chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r,
579
  ike_sa_t *rekey, shared_key_t *shared, auth_method_t method)
580
0
{
581
0
  enumerator_t *enumerator;
582
0
  entry_t *entry;
583
0
  bool keep;
584
585
0
  this->mutex->lock(this->mutex);
586
0
  enumerator = this->listeners->create_enumerator(this->listeners);
587
0
  while (enumerator->enumerate(enumerator, &entry))
588
0
  {
589
0
    if (entry->calling || !entry->listener->ike_keys)
590
0
    {
591
0
      continue;
592
0
    }
593
0
    entry->calling++;
594
0
    keep = entry->listener->ike_keys(entry->listener, ike_sa, kes, dh_other,
595
0
                     nonce_i, nonce_r, rekey, shared,
596
0
                     method);
597
0
    entry->calling--;
598
0
    if (!keep)
599
0
    {
600
0
      unregister_listener(this, entry, enumerator);
601
0
    }
602
0
  }
603
0
  enumerator->destroy(enumerator);
604
0
  this->mutex->unlock(this->mutex);
605
0
}
606
607
METHOD(bus_t, ike_derived_keys, void,
608
  private_bus_t *this, chunk_t sk_d, chunk_t sk_ai, chunk_t sk_ar,
609
  chunk_t sk_ei, chunk_t sk_er, chunk_t sk_pi, chunk_t sk_pr)
610
0
{
611
0
  enumerator_t *enumerator;
612
0
  ike_sa_t *ike_sa;
613
0
  entry_t *entry;
614
0
  bool keep;
615
616
0
  ike_sa = this->thread_sa->get(this->thread_sa);
617
618
0
  this->mutex->lock(this->mutex);
619
0
  enumerator = this->listeners->create_enumerator(this->listeners);
620
0
  while (enumerator->enumerate(enumerator, &entry))
621
0
  {
622
0
    if (entry->calling || !entry->listener->ike_derived_keys)
623
0
    {
624
0
      continue;
625
0
    }
626
0
    entry->calling++;
627
0
    keep = entry->listener->ike_derived_keys(entry->listener, ike_sa, sk_d,
628
0
                         sk_ai, sk_ar, sk_ei, sk_er,
629
0
                         sk_pi, sk_pr);
630
0
    entry->calling--;
631
0
    if (!keep)
632
0
    {
633
0
      unregister_listener(this, entry, enumerator);
634
0
    }
635
0
  }
636
0
  enumerator->destroy(enumerator);
637
0
  this->mutex->unlock(this->mutex);
638
0
}
639
640
METHOD(bus_t, child_keys, void,
641
  private_bus_t *this, child_sa_t *child_sa, bool initiator,
642
  array_t *kes, chunk_t nonce_i, chunk_t nonce_r)
643
0
{
644
0
  enumerator_t *enumerator;
645
0
  ike_sa_t *ike_sa;
646
0
  entry_t *entry;
647
0
  bool keep;
648
649
0
  ike_sa = this->thread_sa->get(this->thread_sa);
650
651
0
  this->mutex->lock(this->mutex);
652
0
  enumerator = this->listeners->create_enumerator(this->listeners);
653
0
  while (enumerator->enumerate(enumerator, &entry))
654
0
  {
655
0
    if (entry->calling || !entry->listener->child_keys)
656
0
    {
657
0
      continue;
658
0
    }
659
0
    entry->calling++;
660
0
    keep = entry->listener->child_keys(entry->listener, ike_sa,
661
0
                child_sa, initiator, kes, nonce_i, nonce_r);
662
0
    entry->calling--;
663
0
    if (!keep)
664
0
    {
665
0
      unregister_listener(this, entry, enumerator);
666
0
    }
667
0
  }
668
0
  enumerator->destroy(enumerator);
669
0
  this->mutex->unlock(this->mutex);
670
0
}
671
672
METHOD(bus_t, child_derived_keys, void,
673
  private_bus_t *this, child_sa_t *child_sa, bool initiator,
674
  chunk_t encr_i, chunk_t encr_r, chunk_t integ_i, chunk_t integ_r)
675
0
{
676
0
  enumerator_t *enumerator;
677
0
  ike_sa_t *ike_sa;
678
0
  entry_t *entry;
679
0
  bool keep;
680
681
0
  ike_sa = this->thread_sa->get(this->thread_sa);
682
683
0
  this->mutex->lock(this->mutex);
684
0
  enumerator = this->listeners->create_enumerator(this->listeners);
685
0
  while (enumerator->enumerate(enumerator, &entry))
686
0
  {
687
0
    if (entry->calling || !entry->listener->child_derived_keys)
688
0
    {
689
0
      continue;
690
0
    }
691
0
    entry->calling++;
692
0
    keep = entry->listener->child_derived_keys(entry->listener, ike_sa,
693
0
                      child_sa, initiator, encr_i, encr_r,
694
0
                      integ_i, integ_r);
695
0
    entry->calling--;
696
0
    if (!keep)
697
0
    {
698
0
      unregister_listener(this, entry, enumerator);
699
0
    }
700
0
  }
701
0
  enumerator->destroy(enumerator);
702
0
  this->mutex->unlock(this->mutex);
703
0
}
704
705
METHOD(bus_t, child_updown, void,
706
  private_bus_t *this, child_sa_t *child_sa, bool up)
707
0
{
708
0
  enumerator_t *enumerator;
709
0
  ike_sa_t *ike_sa;
710
0
  entry_t *entry;
711
0
  bool keep;
712
713
0
  ike_sa = this->thread_sa->get(this->thread_sa);
714
715
0
  this->mutex->lock(this->mutex);
716
0
  enumerator = this->listeners->create_enumerator(this->listeners);
717
0
  while (enumerator->enumerate(enumerator, &entry))
718
0
  {
719
0
    if (entry->calling || !entry->listener->child_updown)
720
0
    {
721
0
      continue;
722
0
    }
723
0
    entry->calling++;
724
0
    keep = entry->listener->child_updown(entry->listener,
725
0
                       ike_sa, child_sa, up);
726
0
    entry->calling--;
727
0
    if (!keep)
728
0
    {
729
0
      unregister_listener(this, entry, enumerator);
730
0
    }
731
0
  }
732
0
  enumerator->destroy(enumerator);
733
0
  this->mutex->unlock(this->mutex);
734
0
}
735
736
METHOD(bus_t, child_rekey, void,
737
  private_bus_t *this, child_sa_t *old, child_sa_t *new)
738
0
{
739
0
  enumerator_t *enumerator;
740
0
  ike_sa_t *ike_sa;
741
0
  entry_t *entry;
742
0
  bool keep;
743
744
0
  ike_sa = this->thread_sa->get(this->thread_sa);
745
746
0
  this->mutex->lock(this->mutex);
747
0
  enumerator = this->listeners->create_enumerator(this->listeners);
748
0
  while (enumerator->enumerate(enumerator, &entry))
749
0
  {
750
0
    if (entry->calling || !entry->listener->child_rekey)
751
0
    {
752
0
      continue;
753
0
    }
754
0
    entry->calling++;
755
0
    keep = entry->listener->child_rekey(entry->listener, ike_sa,
756
0
                      old, new);
757
0
    entry->calling--;
758
0
    if (!keep)
759
0
    {
760
0
      unregister_listener(this, entry, enumerator);
761
0
    }
762
0
  }
763
0
  enumerator->destroy(enumerator);
764
0
  this->mutex->unlock(this->mutex);
765
0
}
766
767
METHOD(bus_t, children_migrate, void,
768
  private_bus_t *this, ike_sa_id_t *new, uint32_t unique)
769
0
{
770
0
  enumerator_t *enumerator;
771
0
  ike_sa_t *ike_sa;
772
0
  entry_t *entry;
773
0
  bool keep;
774
775
0
  ike_sa = this->thread_sa->get(this->thread_sa);
776
777
0
  this->mutex->lock(this->mutex);
778
0
  enumerator = this->listeners->create_enumerator(this->listeners);
779
0
  while (enumerator->enumerate(enumerator, &entry))
780
0
  {
781
0
    if (entry->calling || !entry->listener->children_migrate)
782
0
    {
783
0
      continue;
784
0
    }
785
0
    entry->calling++;
786
0
    keep = entry->listener->children_migrate(entry->listener, ike_sa, new,
787
0
                         unique);
788
0
    entry->calling--;
789
0
    if (!keep)
790
0
    {
791
0
      unregister_listener(this, entry, enumerator);
792
0
    }
793
0
  }
794
0
  enumerator->destroy(enumerator);
795
0
  this->mutex->unlock(this->mutex);
796
0
}
797
798
METHOD(bus_t, ike_updown, void,
799
  private_bus_t *this, ike_sa_t *ike_sa, bool up)
800
0
{
801
0
  enumerator_t *enumerator;
802
0
  entry_t *entry;
803
0
  bool keep;
804
805
0
  this->mutex->lock(this->mutex);
806
0
  enumerator = this->listeners->create_enumerator(this->listeners);
807
0
  while (enumerator->enumerate(enumerator, &entry))
808
0
  {
809
0
    if (entry->calling || !entry->listener->ike_updown)
810
0
    {
811
0
      continue;
812
0
    }
813
0
    entry->calling++;
814
0
    keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
815
0
    entry->calling--;
816
0
    if (!keep)
817
0
    {
818
0
      unregister_listener(this, entry, enumerator);
819
0
    }
820
0
  }
821
0
  enumerator->destroy(enumerator);
822
0
  this->mutex->unlock(this->mutex);
823
824
  /* a down event for IKE_SA implicitly downs all CHILD_SAs */
825
0
  if (!up)
826
0
  {
827
0
    enumerator_t *enumerator;
828
0
    child_sa_t *child_sa;
829
830
0
    enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
831
0
    while (enumerator->enumerate(enumerator, (void**)&child_sa))
832
0
    {
833
0
      switch (child_sa->get_state(child_sa))
834
0
      {
835
0
        case CHILD_REKEYED:
836
0
        case CHILD_DELETED:
837
0
          continue;
838
0
        case CHILD_DELETING:
839
0
          if (child_sa->get_outbound_state(child_sa) ==
840
0
            CHILD_OUTBOUND_NONE)
841
0
          {
842
            /* deleting CHILD_SA has been rekeyed, omit event */
843
0
            continue;
844
0
          }
845
0
          break;
846
0
        default:
847
0
          break;
848
0
      }
849
0
      child_updown(this, child_sa, FALSE);
850
0
    }
851
0
    enumerator->destroy(enumerator);
852
0
  }
853
0
}
854
855
METHOD(bus_t, ike_rekey, void,
856
  private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
857
0
{
858
0
  enumerator_t *enumerator;
859
0
  entry_t *entry;
860
0
  bool keep;
861
862
0
  this->mutex->lock(this->mutex);
863
0
  enumerator = this->listeners->create_enumerator(this->listeners);
864
0
  while (enumerator->enumerate(enumerator, &entry))
865
0
  {
866
0
    if (entry->calling || !entry->listener->ike_rekey)
867
0
    {
868
0
      continue;
869
0
    }
870
0
    entry->calling++;
871
0
    keep = entry->listener->ike_rekey(entry->listener, old, new);
872
0
    entry->calling--;
873
0
    if (!keep)
874
0
    {
875
0
      unregister_listener(this, entry, enumerator);
876
0
    }
877
0
  }
878
0
  enumerator->destroy(enumerator);
879
0
  this->mutex->unlock(this->mutex);
880
0
}
881
882
METHOD(bus_t, ike_update, void,
883
  private_bus_t *this, ike_sa_t *ike_sa, host_t *local, host_t *remote)
884
0
{
885
0
  enumerator_t *enumerator;
886
0
  entry_t *entry;
887
0
  bool keep;
888
889
0
  this->mutex->lock(this->mutex);
890
0
  enumerator = this->listeners->create_enumerator(this->listeners);
891
0
  while (enumerator->enumerate(enumerator, &entry))
892
0
  {
893
0
    if (entry->calling || !entry->listener->ike_update)
894
0
    {
895
0
      continue;
896
0
    }
897
0
    entry->calling++;
898
0
    keep = entry->listener->ike_update(entry->listener, ike_sa, local,
899
0
                       remote);
900
0
    entry->calling--;
901
0
    if (!keep)
902
0
    {
903
0
      unregister_listener(this, entry, enumerator);
904
0
    }
905
0
  }
906
0
  enumerator->destroy(enumerator);
907
0
  this->mutex->unlock(this->mutex);
908
0
}
909
910
METHOD(bus_t, ike_reestablish_pre, void,
911
  private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
912
0
{
913
0
  enumerator_t *enumerator;
914
0
  entry_t *entry;
915
0
  bool keep;
916
917
0
  this->mutex->lock(this->mutex);
918
0
  enumerator = this->listeners->create_enumerator(this->listeners);
919
0
  while (enumerator->enumerate(enumerator, &entry))
920
0
  {
921
0
    if (entry->calling || !entry->listener->ike_reestablish_pre)
922
0
    {
923
0
      continue;
924
0
    }
925
0
    entry->calling++;
926
0
    keep = entry->listener->ike_reestablish_pre(entry->listener, old, new);
927
0
    entry->calling--;
928
0
    if (!keep)
929
0
    {
930
0
      unregister_listener(this, entry, enumerator);
931
0
    }
932
0
  }
933
0
  enumerator->destroy(enumerator);
934
0
  this->mutex->unlock(this->mutex);
935
0
}
936
937
METHOD(bus_t, ike_reestablish_post, void,
938
  private_bus_t *this, ike_sa_t *old, ike_sa_t *new, bool initiated)
939
0
{
940
0
  enumerator_t *enumerator;
941
0
  entry_t *entry;
942
0
  bool keep;
943
944
0
  this->mutex->lock(this->mutex);
945
0
  enumerator = this->listeners->create_enumerator(this->listeners);
946
0
  while (enumerator->enumerate(enumerator, &entry))
947
0
  {
948
0
    if (entry->calling || !entry->listener->ike_reestablish_post)
949
0
    {
950
0
      continue;
951
0
    }
952
0
    entry->calling++;
953
0
    keep = entry->listener->ike_reestablish_post(entry->listener, old, new,
954
0
                           initiated);
955
0
    entry->calling--;
956
0
    if (!keep)
957
0
    {
958
0
      unregister_listener(this, entry, enumerator);
959
0
    }
960
0
  }
961
0
  enumerator->destroy(enumerator);
962
0
  this->mutex->unlock(this->mutex);
963
0
}
964
965
METHOD(bus_t, authorize, bool,
966
  private_bus_t *this, bool final)
967
0
{
968
0
  enumerator_t *enumerator;
969
0
  ike_sa_t *ike_sa;
970
0
  entry_t *entry;
971
0
  bool keep, success = TRUE;
972
973
0
  ike_sa = this->thread_sa->get(this->thread_sa);
974
975
0
  this->mutex->lock(this->mutex);
976
0
  enumerator = this->listeners->create_enumerator(this->listeners);
977
0
  while (enumerator->enumerate(enumerator, &entry))
978
0
  {
979
0
    if (entry->calling || !entry->listener->authorize)
980
0
    {
981
0
      continue;
982
0
    }
983
0
    entry->calling++;
984
0
    keep = entry->listener->authorize(entry->listener, ike_sa,
985
0
                      final, &success);
986
0
    entry->calling--;
987
0
    if (!keep)
988
0
    {
989
0
      unregister_listener(this, entry, enumerator);
990
0
    }
991
0
    if (!success)
992
0
    {
993
0
      break;
994
0
    }
995
0
  }
996
0
  enumerator->destroy(enumerator);
997
0
  this->mutex->unlock(this->mutex);
998
0
  if (!success)
999
0
  {
1000
0
    alert(this, ALERT_AUTHORIZATION_FAILED);
1001
0
  }
1002
0
  return success;
1003
0
}
1004
1005
METHOD(bus_t, narrow, void,
1006
  private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
1007
  linked_list_t *local, linked_list_t *remote)
1008
0
{
1009
0
  enumerator_t *enumerator;
1010
0
  ike_sa_t *ike_sa;
1011
0
  entry_t *entry;
1012
0
  bool keep;
1013
1014
0
  ike_sa = this->thread_sa->get(this->thread_sa);
1015
1016
0
  this->mutex->lock(this->mutex);
1017
0
  enumerator = this->listeners->create_enumerator(this->listeners);
1018
0
  while (enumerator->enumerate(enumerator, &entry))
1019
0
  {
1020
0
    if (entry->calling || !entry->listener->narrow)
1021
0
    {
1022
0
      continue;
1023
0
    }
1024
0
    entry->calling++;
1025
0
    keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
1026
0
                     type, local, remote);
1027
0
    entry->calling--;
1028
0
    if (!keep)
1029
0
    {
1030
0
      unregister_listener(this, entry, enumerator);
1031
0
    }
1032
0
  }
1033
0
  enumerator->destroy(enumerator);
1034
0
  this->mutex->unlock(this->mutex);
1035
0
}
1036
1037
METHOD(bus_t, assign_vips, void,
1038
  private_bus_t *this, ike_sa_t *ike_sa, bool assign)
1039
0
{
1040
0
  enumerator_t *enumerator;
1041
0
  entry_t *entry;
1042
0
  bool keep;
1043
1044
0
  this->mutex->lock(this->mutex);
1045
0
  enumerator = this->listeners->create_enumerator(this->listeners);
1046
0
  while (enumerator->enumerate(enumerator, &entry))
1047
0
  {
1048
0
    if (entry->calling || !entry->listener->assign_vips)
1049
0
    {
1050
0
      continue;
1051
0
    }
1052
0
    entry->calling++;
1053
0
    keep = entry->listener->assign_vips(entry->listener, ike_sa, assign);
1054
0
    entry->calling--;
1055
0
    if (!keep)
1056
0
    {
1057
0
      unregister_listener(this, entry, enumerator);
1058
0
    }
1059
0
  }
1060
0
  enumerator->destroy(enumerator);
1061
0
  this->mutex->unlock(this->mutex);
1062
0
}
1063
1064
METHOD(bus_t, handle_vips, void,
1065
  private_bus_t *this, ike_sa_t *ike_sa, bool handle)
1066
0
{
1067
0
  enumerator_t *enumerator;
1068
0
  entry_t *entry;
1069
0
  bool keep;
1070
1071
0
  this->mutex->lock(this->mutex);
1072
0
  enumerator = this->listeners->create_enumerator(this->listeners);
1073
0
  while (enumerator->enumerate(enumerator, &entry))
1074
0
  {
1075
0
    if (entry->calling || !entry->listener->handle_vips)
1076
0
    {
1077
0
      continue;
1078
0
    }
1079
0
    entry->calling++;
1080
0
    keep = entry->listener->handle_vips(entry->listener, ike_sa, handle);
1081
0
    entry->calling--;
1082
0
    if (!keep)
1083
0
    {
1084
0
      unregister_listener(this, entry, enumerator);
1085
0
    }
1086
0
  }
1087
0
  enumerator->destroy(enumerator);
1088
0
  this->mutex->unlock(this->mutex);
1089
0
}
1090
1091
/**
1092
 * Credential manager hook function to forward bus alerts
1093
 */
1094
static void hook_creds(private_bus_t *this, credential_hook_type_t type,
1095
             certificate_t *cert)
1096
0
{
1097
0
  switch (type)
1098
0
  {
1099
0
    case CRED_HOOK_EXPIRED:
1100
0
      return alert(this, ALERT_CERT_EXPIRED, cert);
1101
0
    case CRED_HOOK_REVOKED:
1102
0
      return alert(this, ALERT_CERT_REVOKED, cert);
1103
0
    case CRED_HOOK_VALIDATION_FAILED:
1104
0
      return alert(this, ALERT_CERT_VALIDATION_FAILED, cert);
1105
0
    case CRED_HOOK_NO_ISSUER:
1106
0
      return alert(this, ALERT_CERT_NO_ISSUER, cert);
1107
0
    case CRED_HOOK_UNTRUSTED_ROOT:
1108
0
      return alert(this, ALERT_CERT_UNTRUSTED_ROOT, cert);
1109
0
    case CRED_HOOK_EXCEEDED_PATH_LEN:
1110
0
      return alert(this, ALERT_CERT_EXCEEDED_PATH_LEN, cert);
1111
0
    case CRED_HOOK_POLICY_VIOLATION:
1112
0
      return alert(this, ALERT_CERT_POLICY_VIOLATION, cert);
1113
0
  }
1114
0
}
1115
1116
METHOD(bus_t, destroy, void,
1117
  private_bus_t *this)
1118
0
{
1119
0
  debug_t group;
1120
1121
0
  lib->credmgr->set_hook(lib->credmgr, NULL, NULL);
1122
0
  for (group = 0; group < DBG_MAX; group++)
1123
0
  {
1124
0
    this->loggers[group]->destroy(this->loggers[group]);
1125
0
  }
1126
0
  this->loggers[DBG_MAX]->destroy_function(this->loggers[DBG_MAX],
1127
0
                       (void*)free);
1128
0
  this->listeners->destroy_function(this->listeners, (void*)free);
1129
0
  this->thread_sa->destroy(this->thread_sa);
1130
0
  this->log_lock->destroy(this->log_lock);
1131
0
  this->mutex->destroy(this->mutex);
1132
0
  free(this);
1133
0
}
1134
1135
/*
1136
 * Described in header.
1137
 */
1138
bus_t *bus_create()
1139
2
{
1140
2
  private_bus_t *this;
1141
2
  debug_t group;
1142
1143
2
  INIT(this,
1144
2
    .public = {
1145
2
      .add_listener = _add_listener,
1146
2
      .remove_listener = _remove_listener,
1147
2
      .add_logger = _add_logger,
1148
2
      .remove_logger = _remove_logger,
1149
2
      .set_sa = _set_sa,
1150
2
      .get_sa = _get_sa,
1151
2
      .log = _log_,
1152
2
      .vlog = _vlog,
1153
2
      .alert = _alert,
1154
2
      .ike_state_change = _ike_state_change,
1155
2
      .child_state_change = _child_state_change,
1156
2
      .message = _message,
1157
2
      .ike_keys = _ike_keys,
1158
2
      .ike_derived_keys = _ike_derived_keys,
1159
2
      .child_keys = _child_keys,
1160
2
      .child_derived_keys = _child_derived_keys,
1161
2
      .ike_updown = _ike_updown,
1162
2
      .ike_rekey = _ike_rekey,
1163
2
      .ike_update = _ike_update,
1164
2
      .ike_reestablish_pre = _ike_reestablish_pre,
1165
2
      .ike_reestablish_post = _ike_reestablish_post,
1166
2
      .child_updown = _child_updown,
1167
2
      .child_rekey = _child_rekey,
1168
2
      .children_migrate = _children_migrate,
1169
2
      .authorize = _authorize,
1170
2
      .narrow = _narrow,
1171
2
      .assign_vips = _assign_vips,
1172
2
      .handle_vips = _handle_vips,
1173
2
      .destroy = _destroy,
1174
2
    },
1175
2
    .listeners = linked_list_create(),
1176
2
    .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1177
2
    .log_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1178
2
    .thread_sa = thread_value_create(NULL),
1179
2
  );
1180
1181
42
  for (group = 0; group <= DBG_MAX; group++)
1182
40
  {
1183
40
    this->loggers[group] = linked_list_create();
1184
40
    this->max_level[group] = LEVEL_SILENT;
1185
40
    this->max_vlevel[group] = LEVEL_SILENT;
1186
40
  }
1187
1188
2
  lib->credmgr->set_hook(lib->credmgr, (credential_hook_t)hook_creds, this);
1189
1190
2
  return &this->public;
1191
2
}