Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/settings/settings_types.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2010-2018 Tobias Brunner
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 "settings_types.h"
18
19
/*
20
 * Described in header
21
 */
22
kv_t *settings_kv_create(char *key, char *value)
23
0
{
24
0
  kv_t *this;
25
26
0
  INIT(this,
27
0
    .key = key,
28
0
    .value = value,
29
0
  );
30
0
  return this;
31
0
}
32
33
/*
34
 * Described in header
35
 */
36
void settings_kv_destroy(kv_t *this, array_t *contents)
37
0
{
38
0
  free(this->key);
39
0
  if (contents && this->value)
40
0
  {
41
0
    array_insert(contents, ARRAY_TAIL, this->value);
42
0
  }
43
0
  else
44
0
  {
45
0
    free(this->value);
46
0
  }
47
0
  free(this);
48
0
}
49
50
/*
51
 * Described in header
52
 */
53
section_t *settings_section_create(char *name)
54
15.6k
{
55
15.6k
  section_t *this;
56
57
15.6k
  INIT(this,
58
15.6k
    .name = name,
59
15.6k
  );
60
15.6k
  return this;
61
15.6k
}
62
63
static void section_destroy(section_t *section, int idx, array_t *contents)
64
3.92k
{
65
3.92k
  settings_section_destroy(section, contents);
66
3.92k
}
67
68
static void kv_destroy(kv_t *kv, int idx, array_t *contents)
69
0
{
70
0
  settings_kv_destroy(kv, contents);
71
0
}
72
73
static void ref_destroy(section_ref_t *ref, int idx, void *ctx)
74
3.92k
{
75
3.92k
  free(ref->name);
76
3.92k
  free(ref);
77
3.92k
}
78
79
/*
80
 * Described in header
81
 */
82
void settings_section_destroy(section_t *this, array_t *contents)
83
15.6k
{
84
15.6k
  array_destroy_function(this->sections, (void*)section_destroy, contents);
85
15.6k
  array_destroy(this->sections_order);
86
15.6k
  array_destroy_function(this->kv, (void*)kv_destroy, contents);
87
15.6k
  array_destroy(this->kv_order);
88
15.6k
  array_destroy_function(this->references, (void*)ref_destroy, NULL);
89
15.6k
  free(this->name);
90
15.6k
  free(this);
91
15.6k
}
92
93
/*
94
 * Described in header
95
 */
96
void settings_kv_set(kv_t *kv, char *value, array_t *contents)
97
0
{
98
0
  if (value && kv->value && streq(value, kv->value))
99
0
  { /* no update required */
100
0
    free(value);
101
0
    return;
102
0
  }
103
104
  /* if the new value was shorter we could overwrite the existing one but that
105
   * could lead to reads of partially updated values from other threads that
106
   * have a pointer to the existing value, so we replace it anyway */
107
0
  if (kv->value && contents)
108
0
  {
109
0
    array_insert(contents, ARRAY_TAIL, kv->value);
110
0
  }
111
0
  else
112
0
  {
113
0
    free(kv->value);
114
0
  }
115
0
  kv->value = value;
116
0
}
117
118
/*
119
 * Described in header
120
 */
121
void settings_kv_add(section_t *section, kv_t *kv, array_t *contents)
122
0
{
123
0
  kv_t *found;
124
125
0
  if (array_bsearch(section->kv, kv->key, settings_kv_find, &found) == -1)
126
0
  {
127
0
    array_insert_create(&section->kv, ARRAY_TAIL, kv);
128
0
    array_sort(section->kv, settings_kv_sort, NULL);
129
0
    array_insert_create(&section->kv_order, ARRAY_TAIL, kv);
130
0
  }
131
0
  else
132
0
  {
133
0
    settings_kv_set(found, kv->value, contents);
134
0
    kv->value = NULL;
135
0
    settings_kv_destroy(kv, NULL);
136
0
  }
137
0
}
138
139
/*
140
 * Described in header
141
 */
142
void settings_reference_add(section_t *section, char *name, bool permanent)
143
3.92k
{
144
3.92k
  section_ref_t *ref;
145
3.92k
  int i;
146
147
3.92k
  for (i = 0; i < array_count(section->references); i++)
148
0
  {
149
0
    array_get(section->references, i, &ref);
150
0
    if (ref->permanent && !permanent)
151
0
    { /* add it before any permanent references */
152
0
      break;
153
0
    }
154
0
    if (ref->permanent == permanent && streq(name, ref->name))
155
0
    {
156
0
      free(name);
157
0
      return;
158
0
    }
159
0
  }
160
161
3.92k
  INIT(ref,
162
3.92k
    .name = name,
163
3.92k
    .permanent = permanent,
164
3.92k
  );
165
3.92k
  array_insert_create(&section->references, i, ref);
166
3.92k
}
167
168
/*
169
 * Add a section to the given parent, optionally remove settings/subsections
170
 * not found when extending an existing section
171
 */
172
static void add_section(section_t *parent, section_t *section,
173
            array_t *contents, bool purge)
174
3.92k
{
175
3.92k
  section_t *found;
176
177
3.92k
  if (array_bsearch(parent->sections, section->name, settings_section_find,
178
3.92k
            &found) == -1)
179
3.92k
  {
180
3.92k
    array_insert_create(&parent->sections, ARRAY_TAIL, section);
181
3.92k
    array_sort(parent->sections, settings_section_sort, NULL);
182
3.92k
    array_insert_create(&parent->sections_order, ARRAY_TAIL, section);
183
3.92k
  }
184
0
  else
185
0
  {
186
0
    settings_section_extend(found, section, contents, purge);
187
0
    settings_section_destroy(section, contents);
188
0
  }
189
3.92k
}
190
191
/*
192
 * Described in header
193
 */
194
void settings_section_add(section_t *parent, section_t *section,
195
              array_t *contents)
196
3.92k
{
197
3.92k
  add_section(parent, section, contents, FALSE);
198
3.92k
}
199
200
/**
201
 * Purge contents of a section, returns TRUE if section can be safely removed.
202
 */
203
static bool section_purge(section_t *this, array_t *contents)
204
0
{
205
0
  section_t *current;
206
0
  section_ref_t *ref;
207
0
  int i, idx;
208
209
0
  array_destroy_function(this->kv, (void*)kv_destroy, contents);
210
0
  this->kv = NULL;
211
0
  array_destroy(this->kv_order);
212
0
  this->kv_order = NULL;
213
  /* remove non-permanent references */
214
0
  for (i = array_count(this->references) - 1; i >= 0; i--)
215
0
  {
216
0
    array_get(this->references, i, &ref);
217
0
    if (!ref->permanent)
218
0
    {
219
0
      array_remove(this->references, i, NULL);
220
0
      ref_destroy(ref, 0, NULL);
221
0
    }
222
0
  }
223
0
  if (!array_count(this->references))
224
0
  {
225
0
    array_destroy(this->references);
226
0
    this->references = NULL;
227
0
  }
228
0
  for (i = array_count(this->sections_order) - 1; i >= 0; i--)
229
0
  {
230
0
    array_get(this->sections_order, i, &current);
231
0
    if (section_purge(current, contents))
232
0
    {
233
0
      array_remove(this->sections_order, i, NULL);
234
0
      idx = array_bsearch(this->sections, current->name,
235
0
                settings_section_find, NULL);
236
0
      array_remove(this->sections, idx, NULL);
237
0
      settings_section_destroy(current, contents);
238
0
    }
239
0
  }
240
  /* we ensure sections configured with permanent references (or having any
241
   * such subsections) are not removed */
242
0
  return !this->references && !array_count(this->sections);
243
0
}
244
245
/*
246
 * Described in header
247
 */
248
void settings_section_extend(section_t *base, section_t *extension,
249
               array_t *contents, bool purge)
250
3.92k
{
251
3.92k
  enumerator_t *enumerator;
252
3.92k
  section_t *section;
253
3.92k
  section_ref_t *ref;
254
3.92k
  kv_t *kv;
255
3.92k
  array_t *sections = NULL, *kvs = NULL;
256
3.92k
  int idx;
257
258
3.92k
  if (purge)
259
3.92k
  { /* remove sections, settings in base not found in extension, the others
260
     * are removed too (from the _order list) so they can be inserted in the
261
     * order found in extension, non-permanent references are removed */
262
3.92k
    enumerator = array_create_enumerator(base->sections_order);
263
3.92k
    while (enumerator->enumerate(enumerator, (void**)&section))
264
0
    {
265
0
      if (array_bsearch(extension->sections, section->name,
266
0
                settings_section_find, NULL) == -1)
267
0
      {
268
0
        idx = array_bsearch(base->sections, section->name,
269
0
                  settings_section_find, NULL);
270
0
        if (section_purge(section, contents))
271
0
        { /* only remove them if we can purge them */
272
0
          array_remove(base->sections, idx, NULL);
273
0
          array_remove_at(base->sections_order, enumerator);
274
0
          settings_section_destroy(section, contents);
275
0
        }
276
0
      }
277
0
      else
278
0
      {
279
0
        array_remove_at(base->sections_order, enumerator);
280
0
        array_insert_create(&sections, ARRAY_TAIL, section);
281
0
        array_sort(sections, settings_section_sort, NULL);
282
0
      }
283
0
    }
284
3.92k
    enumerator->destroy(enumerator);
285
286
3.92k
    while (array_remove(base->kv_order, 0, &kv))
287
0
    {
288
0
      if (array_bsearch(extension->kv, kv->key, settings_kv_find,
289
0
                NULL) == -1)
290
0
      {
291
0
        idx = array_bsearch(base->kv, kv->key, settings_kv_find, NULL);
292
0
        array_remove(base->kv, idx, NULL);
293
0
        settings_kv_destroy(kv, contents);
294
0
      }
295
0
      else
296
0
      {
297
0
        array_insert_create(&kvs, ARRAY_TAIL, kv);
298
0
        array_sort(kvs, settings_kv_sort, NULL);
299
0
      }
300
0
    }
301
302
3.92k
    enumerator = array_create_enumerator(base->references);
303
3.92k
    while (enumerator->enumerate(enumerator, (void**)&ref))
304
0
    {
305
0
      if (ref->permanent)
306
0
      { /* permanent references are ignored */
307
0
        continue;
308
0
      }
309
0
      array_remove_at(base->references, enumerator);
310
0
      ref_destroy(ref, 0, NULL);
311
0
    }
312
3.92k
    enumerator->destroy(enumerator);
313
3.92k
  }
314
315
3.92k
  while (array_remove(extension->sections_order, 0, &section))
316
0
  {
317
0
    idx = array_bsearch(sections, section->name,
318
0
              settings_section_find, NULL);
319
0
    if (idx != -1)
320
0
    {
321
0
      section_t *existing;
322
323
0
      array_remove(sections, idx, &existing);
324
0
      array_insert(base->sections_order, ARRAY_TAIL, existing);
325
0
    }
326
0
    idx = array_bsearch(extension->sections, section->name,
327
0
              settings_section_find, NULL);
328
0
    array_remove(extension->sections, idx, NULL);
329
0
    add_section(base, section, contents, purge);
330
0
  }
331
332
3.92k
  while (array_remove(extension->kv_order, 0, &kv))
333
0
  {
334
0
    idx = array_bsearch(kvs, kv->key, settings_kv_find, NULL);
335
0
    if (idx != -1)
336
0
    {
337
0
      kv_t *existing;
338
339
0
      array_remove(kvs, idx, &existing);
340
0
      array_insert(base->kv_order, ARRAY_TAIL, existing);
341
0
    }
342
0
    idx = array_bsearch(extension->kv, kv->key, settings_kv_find, NULL);
343
0
    array_remove(extension->kv, idx, NULL);
344
0
    settings_kv_add(base, kv, contents);
345
0
  }
346
347
3.92k
  while (array_remove(extension->references, 0, &ref))
348
0
  {
349
0
    if (ref->permanent)
350
0
    { /* ignore permanent references in the extension */
351
0
      continue;
352
0
    }
353
0
    settings_reference_add(base, strdup(ref->name), FALSE);
354
0
    ref_destroy(ref, 0, NULL);
355
0
  }
356
3.92k
  array_destroy(sections);
357
3.92k
  array_destroy(kvs);
358
3.92k
}
359
360
/*
361
 * Described in header
362
 */
363
int settings_section_find(const void *a, const void *b)
364
214k
{
365
214k
  const char *key = a;
366
214k
  const section_t *item = b;
367
214k
  return strcmp(key, item->name);
368
214k
}
369
370
/*
371
 * Described in header
372
 */
373
int settings_section_sort(const void *a, const void *b, void *user)
374
0
{
375
0
  const section_t *sa = a, *sb = b;
376
0
  return strcmp(sa->name, sb->name);
377
0
}
378
379
/*
380
 * Described in header
381
 */
382
int settings_kv_find(const void *a, const void *b)
383
0
{
384
0
  const char *key = a;
385
0
  const kv_t *item = b;
386
0
  return strcmp(key, item->key);
387
0
}
388
389
/*
390
 * Described in header
391
 */
392
int settings_kv_sort(const void *a, const void *b, void *user)
393
0
{
394
0
  const kv_t *kva = a, *kvb = b;
395
0
  return strcmp(kva->key, kvb->key);
396
0
}