Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/credentials/cred_encoding.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2009 Martin Willi
3
 *
4
 * Copyright (C) secunet Security Networks AG
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 2 of the License, or (at your
9
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
10
 *
11
 * This program is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * for more details.
15
 */
16
17
#include "cred_encoding.h"
18
19
#include <stdint.h>
20
21
#include <collections/linked_list.h>
22
#include <collections/hashtable.h>
23
#include <threading/rwlock.h>
24
25
typedef struct private_cred_encoding_t private_cred_encoding_t;
26
27
/**
28
 * Private data of an cred_encoding_t object.
29
 */
30
struct private_cred_encoding_t {
31
32
  /**
33
   * Public cred_encoding_t interface.
34
   */
35
  cred_encoding_t public;
36
37
  /**
38
   * cached encodings, a table for each encoding_type_t, containing chunk_t*
39
   */
40
  hashtable_t *cache[CRED_ENCODING_MAX];
41
42
  /**
43
   * Registered encoding functions, cred_encoder_t
44
   */
45
  linked_list_t *encoders;
46
47
  /**
48
   * lock to access cache/encoders
49
   */
50
  rwlock_t *lock;
51
};
52
53
/**
54
 * See header.
55
 */
56
bool cred_encoding_args(va_list args, ...)
57
0
{
58
0
  va_list parts, copy;
59
0
  bool failed = FALSE;
60
61
0
  va_start(parts, args);
62
63
0
  while (!failed)
64
0
  {
65
0
    cred_encoding_part_t current, target;
66
0
    chunk_t *out, data;
67
68
    /* get the part we are looking for */
69
0
    target = va_arg(parts, cred_encoding_part_t);
70
0
    if (target == CRED_PART_END)
71
0
    {
72
0
      break;
73
0
    }
74
0
    out = va_arg(parts, chunk_t*);
75
76
0
    va_copy(copy, args);
77
0
    while (!failed)
78
0
    {
79
0
      current = va_arg(copy, cred_encoding_part_t);
80
0
      if (current == CRED_PART_END)
81
0
      {
82
0
        failed = TRUE;
83
0
        break;
84
0
      }
85
0
      data = va_arg(copy, chunk_t);
86
0
      if (current == target)
87
0
      {
88
0
        *out = data;
89
0
        break;
90
0
      }
91
0
    }
92
0
    va_end(copy);
93
0
  }
94
0
  va_end(parts);
95
0
  return !failed;
96
0
}
97
98
METHOD(cred_encoding_t, get_cache, bool,
99
  private_cred_encoding_t *this, cred_encoding_type_t type, void *cache,
100
  chunk_t *encoding)
101
0
{
102
0
  chunk_t *chunk;
103
104
0
  if (type >= CRED_ENCODING_MAX || (int)type < 0)
105
0
  {
106
0
    return FALSE;
107
0
  }
108
0
  this->lock->read_lock(this->lock);
109
0
  chunk = this->cache[type]->get(this->cache[type], cache);
110
0
  if (chunk)
111
0
  {
112
0
    *encoding = *chunk;
113
0
  }
114
0
  this->lock->unlock(this->lock);
115
0
  return !!chunk;
116
0
}
117
118
METHOD(cred_encoding_t, cache, void,
119
  private_cred_encoding_t *this, cred_encoding_type_t type, void *cache,
120
  chunk_t *encoding)
121
0
{
122
0
  chunk_t *chunk;
123
124
0
  if (type >= CRED_ENCODING_MAX || (int)type < 0)
125
0
  {
126
0
    free(encoding->ptr);
127
0
    return;
128
0
  }
129
130
0
  this->lock->write_lock(this->lock);
131
0
  chunk = this->cache[type]->get(this->cache[type], cache);
132
0
  if (chunk)
133
0
  {
134
0
    free(encoding->ptr);
135
0
    *encoding = *chunk;
136
0
  }
137
0
  else
138
0
  {
139
0
    chunk = malloc_thing(chunk_t);
140
0
    *chunk = *encoding;
141
0
    this->cache[type]->put(this->cache[type], cache, chunk);
142
0
  }
143
0
  this->lock->unlock(this->lock);
144
0
}
145
146
/**
147
 * Implementation of cred_encoding_t.encode
148
 */
149
static bool encode(private_cred_encoding_t *this, cred_encoding_type_t type,
150
           void *cache, chunk_t *encoding, ...)
151
0
{
152
0
  enumerator_t *enumerator;
153
0
  va_list args, copy;
154
0
  cred_encoder_t encode;
155
0
  bool success = FALSE;
156
0
  chunk_t *chunk;
157
158
0
  if (type >= CRED_ENCODING_MAX || (int)type < 0)
159
0
  {
160
0
    return FALSE;
161
0
  }
162
0
  this->lock->read_lock(this->lock);
163
0
  if (cache)
164
0
  {
165
0
    chunk = this->cache[type]->get(this->cache[type], cache);
166
0
    if (chunk)
167
0
    {
168
0
      *encoding = *chunk;
169
0
      this->lock->unlock(this->lock);
170
0
      return TRUE;
171
0
    }
172
0
  }
173
0
  va_start(args, encoding);
174
0
  enumerator = this->encoders->create_enumerator(this->encoders);
175
0
  while (enumerator->enumerate(enumerator, &encode))
176
0
  {
177
0
    va_copy(copy, args);
178
0
    success = encode(type, encoding, copy);
179
0
    va_end(copy);
180
0
    if (success)
181
0
    {
182
0
      break;
183
0
    }
184
0
  }
185
0
  enumerator->destroy(enumerator);
186
0
  this->lock->unlock(this->lock);
187
0
  va_end(args);
188
189
0
  if (success && cache)
190
0
  {
191
0
    _cache(this, type, cache, encoding);
192
0
  }
193
0
  return success;
194
0
}
195
196
METHOD(cred_encoding_t, clear_cache, void,
197
  private_cred_encoding_t *this, void *cache)
198
0
{
199
0
  cred_encoding_type_t type;
200
0
  chunk_t *chunk;
201
202
0
  this->lock->write_lock(this->lock);
203
0
  for (type = 0; type < CRED_ENCODING_MAX; type++)
204
0
  {
205
0
    chunk = this->cache[type]->remove(this->cache[type], cache);
206
0
    if (chunk)
207
0
    {
208
0
      chunk_free(chunk);
209
0
      free(chunk);
210
0
    }
211
0
  }
212
0
  this->lock->unlock(this->lock);
213
0
}
214
215
METHOD(cred_encoding_t, add_encoder, void,
216
  private_cred_encoding_t *this, cred_encoder_t encoder)
217
7.84k
{
218
7.84k
  this->lock->write_lock(this->lock);
219
7.84k
  this->encoders->insert_last(this->encoders, encoder);
220
7.84k
  this->lock->unlock(this->lock);
221
7.84k
}
222
223
METHOD(cred_encoding_t, remove_encoder, void,
224
  private_cred_encoding_t *this, cred_encoder_t encoder)
225
7.84k
{
226
7.84k
  this->lock->write_lock(this->lock);
227
7.84k
  this->encoders->remove(this->encoders, encoder, NULL);
228
7.84k
  this->lock->unlock(this->lock);
229
7.84k
}
230
231
METHOD(cred_encoding_t, destroy, void,
232
  private_cred_encoding_t *this)
233
3.92k
{
234
3.92k
  cred_encoding_type_t type;
235
236
74.4k
  for (type = 0; type < CRED_ENCODING_MAX; type++)
237
70.5k
  {
238
    /* We explicitly do not free remaining encodings. All creds should
239
     * have gone now, and they are responsible for cleaning out their
240
     * cache entries. Not flushing here allows the leak detective to
241
     * complain if a credential did not flush cached encodings. */
242
70.5k
    this->cache[type]->destroy(this->cache[type]);
243
70.5k
  }
244
3.92k
  this->encoders->destroy(this->encoders);
245
3.92k
  this->lock->destroy(this->lock);
246
3.92k
  free(this);
247
3.92k
}
248
249
/**
250
 * See header
251
 */
252
cred_encoding_t *cred_encoding_create()
253
3.92k
{
254
3.92k
  private_cred_encoding_t *this;
255
3.92k
  cred_encoding_type_t type;
256
257
3.92k
  INIT(this,
258
3.92k
    .public = {
259
3.92k
      .encode = (bool(*)(cred_encoding_t*, cred_encoding_type_t type, void *cache, chunk_t *encoding, ...))encode,
260
3.92k
      .get_cache = _get_cache,
261
3.92k
      .cache = _cache,
262
3.92k
      .clear_cache = _clear_cache,
263
3.92k
      .add_encoder = _add_encoder,
264
3.92k
      .remove_encoder = _remove_encoder,
265
3.92k
      .destroy = _destroy,
266
3.92k
    },
267
3.92k
    .encoders = linked_list_create(),
268
3.92k
    .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
269
3.92k
  );
270
271
74.4k
  for (type = 0; type < CRED_ENCODING_MAX; type++)
272
70.5k
  {
273
70.5k
    this->cache[type] = hashtable_create(hashtable_hash_ptr,
274
70.5k
                       hashtable_equals_ptr, 8);
275
70.5k
  }
276
277
3.92k
  return &this->public;
278
3.92k
}
279