Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/util/profile/t_profile.c
34889 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* util/profile/t_profile.c - profile library regression tests */
3
/*
4
* Copyright (C) 2021 by the Massachusetts Institute of Technology.
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
*
11
* * Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
*
14
* * Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in
16
* the documentation and/or other materials provided with the
17
* distribution.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30
* OF THE POSSIBILITY OF SUCH DAMAGE.
31
*/
32
33
#include <assert.h>
34
#include <stdarg.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <time.h>
39
#include <unistd.h>
40
#include <utime.h>
41
#include "profile.h"
42
43
static void
44
check(long code)
45
{
46
assert(code == 0);
47
}
48
49
static void
50
check_fail(long code, long expected)
51
{
52
assert(code == expected);
53
}
54
55
static void
56
write_file(const char *name, int nlines, ...)
57
{
58
FILE *f;
59
va_list ap;
60
int i;
61
62
(void)unlink(name);
63
f = fopen(name, "w");
64
assert(f != NULL);
65
va_start(ap, nlines);
66
for (i = 0; i < nlines; i++)
67
fprintf(f, "%s\n", va_arg(ap, char *));
68
va_end(ap);
69
fclose(f);
70
}
71
72
/* Regression test for #2685 (profile iterator breaks when modifications
73
* made) */
74
static void
75
test_iterate(void)
76
{
77
profile_t p;
78
void *iter;
79
const char *names[] = { "test section 1", "child_section", "child", NULL };
80
const char *values[] = { "slick", "harry", "john", NULL };
81
char *name, *value;
82
int i;
83
84
check(profile_init_path("test2.ini", &p));
85
86
/* Iterate and check for the expected values. */
87
check(profile_iterator_create(p, names, 0, &iter));
88
for (i = 0;; i++) {
89
check(profile_iterator(&iter, &name, &value));
90
if (name == NULL && value == NULL)
91
break;
92
assert(strcmp(name, names[2]) == 0);
93
assert(values[i] != NULL);
94
assert(strcmp(value, values[i]) == 0);
95
profile_release_string(name);
96
profile_release_string(value);
97
}
98
assert(values[i] == NULL);
99
profile_iterator_free(&iter);
100
101
/* Iterate again, deleting each value as we go. Flush the result to a
102
* separate file. */
103
check(profile_iterator_create(p, names, 0, &iter));
104
for (;;) {
105
check(profile_iterator(&iter, NULL, &value));
106
if (value == NULL)
107
break;
108
check(profile_update_relation(p, names, value, NULL));
109
profile_release_string(value);
110
}
111
profile_iterator_free(&iter);
112
(void)unlink("test3.ini");
113
profile_flush_to_file(p, "test3.ini");
114
115
profile_abandon(p);
116
117
/* Check that no values for the section are found in the resulting file. */
118
check(profile_init_path("test3.ini", &p));
119
check(profile_iterator_create(p, names, 0, &iter));
120
check(profile_iterator(&iter, &name, &value));
121
assert(name == NULL && value == NULL);
122
profile_iterator_free(&iter);
123
profile_abandon(p);
124
}
125
126
/*
127
* Regression test for a 1.4-era bug where updating the underlying file data of
128
* a profile object lost track of the flag indicating that it was part of the
129
* global shared profiles list.
130
*/
131
static void
132
test_shared(void)
133
{
134
profile_t a, b;
135
struct utimbuf times;
136
137
system("cp test2.ini test3.ini");
138
139
/* Create an entry in the shared table. */
140
check(profile_init_path("test3.ini", &a));
141
142
/*
143
* Force an update of the underlying data. With the bug present, the
144
* shared flag is erroneously cleared. The easiest way to force an update
145
* is to reopen the file (since we don't enforce the one-stat-per-second
146
* limit during open) after changing the timestamp.
147
*/
148
times.actime = time(NULL) + 2;
149
times.modtime = times.actime;
150
utime("test3.ini", &times);
151
check(profile_init_path("test3.ini", &b));
152
profile_release(b);
153
154
/* Release the profile. With the bug present, a dangling reference is left
155
* behind in the shared table. */
156
profile_release(a);
157
158
/* Open the profile again to dereference the dangling pointer if one was
159
* created. */
160
check(profile_init_path("test3.ini", &a));
161
profile_release(a);
162
}
163
164
/* Regression test for #2950 (profile_clear_relation not reflected within
165
* handle where deletion is performed) */
166
static void
167
test_clear(void)
168
{
169
profile_t p;
170
const char *names[] = { "test section 1", "quux", NULL };
171
char **values, **dummy;
172
173
check(profile_init_path("test2.ini", &p));
174
check(profile_get_values(p, names, &values));
175
check(profile_clear_relation(p, names));
176
check_fail(profile_get_values(p, names, &dummy), PROF_NO_RELATION);
177
check(profile_add_relation(p, names, values[0]));
178
profile_free_list(values);
179
check(profile_get_values(p, names, &values));
180
assert(values[0] != NULL && values[1] == NULL);
181
profile_free_list(values);
182
profile_abandon(p);
183
}
184
185
static void
186
test_include(void)
187
{
188
profile_t p;
189
const char *names[] = { "test section 1", "bar", NULL };
190
char **values;
191
192
/* Test expected error code when including nonexistent file. */
193
write_file("testinc.ini", 1, "include does-not-exist");
194
check_fail(profile_init_path("testinc.ini", &p), PROF_FAIL_INCLUDE_FILE);
195
196
/* Test expected error code when including nonexistent directory. */
197
write_file("testinc.ini", 1, "includedir does-not-exist");
198
check_fail(profile_init_path("testinc.ini", &p), PROF_FAIL_INCLUDE_DIR);
199
200
/* Test including a file. */
201
write_file("testinc.ini", 1, "include test2.ini");
202
check(profile_init_path("testinc.ini", &p));
203
check(profile_get_values(p, names, &values));
204
assert(strcmp(values[0], "foo") == 0 && values[1] == NULL);
205
profile_free_list(values);
206
profile_release(p);
207
208
/*
209
* Test including a directory. Put four copies of test2.ini inside the
210
* directory, two with invalid names. Check that we get two values for one
211
* of the variables.
212
*/
213
system("rm -rf test_include_dir");
214
system("mkdir test_include_dir");
215
system("cp test2.ini test_include_dir/a");
216
system("cp test2.ini test_include_dir/a~");
217
system("cp test2.ini test_include_dir/b.conf");
218
system("cp test2.ini test_include_dir/b.conf.rpmsave");
219
write_file("testinc.ini", 1, "includedir test_include_dir");
220
check(profile_init_path("testinc.ini", &p));
221
check(profile_get_values(p, names, &values));
222
assert(strcmp(values[0], "foo") == 0);
223
assert(strcmp(values[1], "foo") == 0);
224
assert(values[2] == NULL);
225
profile_free_list(values);
226
profile_release(p);
227
228
/* Directly list the directory in the profile path and try again. */
229
check(profile_init_path("test_include_dir", &p));
230
check(profile_get_values(p, names, &values));
231
assert(strcmp(values[0], "foo") == 0);
232
assert(strcmp(values[1], "foo") == 0);
233
assert(values[2] == NULL);
234
profile_free_list(values);
235
profile_release(p);
236
}
237
238
/* Test syntactic independence of included profile files. */
239
static void
240
test_independence(void)
241
{
242
profile_t p;
243
const char *names1[] = { "sec1", "var", "a", NULL };
244
const char *names2[] = { "sec2", "b", NULL };
245
const char *names3[] = { "sec1", "var", "c", NULL };
246
char **values;
247
248
write_file("testinc.ini", 6, "[sec1]", "var = {", "a = 1",
249
"include testinc2.ini", "c = 3", "}");
250
write_file("testinc2.ini", 2, "[sec2]", "b = 2");
251
252
check(profile_init_path("testinc.ini", &p));
253
check(profile_get_values(p, names1, &values));
254
assert(strcmp(values[0], "1") == 0 && values[1] == NULL);
255
profile_free_list(values);
256
check(profile_get_values(p, names2, &values));
257
assert(strcmp(values[0], "2") == 0 && values[1] == NULL);
258
profile_free_list(values);
259
check(profile_get_values(p, names3, &values));
260
assert(strcmp(values[0], "3") == 0 && values[1] == NULL);
261
profile_free_list(values);
262
profile_release(p);
263
}
264
265
/* Regression test for #7971 (deleted sections should not be iterable) */
266
static void
267
test_delete_section(void)
268
{
269
profile_t p;
270
const char *sect[] = { "test section 1", NULL };
271
const char *newrel[] = { "test section 1", "testkey", NULL };
272
const char *oldrel[] = { "test section 1", "child", NULL };
273
char **values;
274
275
check(profile_init_path("test2.ini", &p));
276
277
/* Remove and replace a section. */
278
check(profile_rename_section(p, sect, NULL));
279
check(profile_add_relation(p, sect, NULL));
280
check(profile_add_relation(p, newrel, "6"));
281
282
/* Check that we can read the new relation but not the old one. */
283
check(profile_get_values(p, newrel, &values));
284
assert(strcmp(values[0], "6") == 0 && values[1] == NULL);
285
profile_free_list(values);
286
check_fail(profile_get_values(p, oldrel, &values), PROF_NO_RELATION);
287
profile_abandon(p);
288
}
289
290
/* Regression test for #7971 (profile_clear_relation() error with deleted node
291
* at end of value set) */
292
static void
293
test_delete_clear_relation(void)
294
{
295
profile_t p;
296
const char *names[] = { "test section 1", "testkey", NULL };
297
298
check(profile_init_path("test2.ini", &p));
299
check(profile_add_relation(p, names, "1"));
300
check(profile_add_relation(p, names, "2"));
301
check(profile_update_relation(p, names, "2", NULL));
302
check(profile_clear_relation(p, names));
303
profile_abandon(p);
304
}
305
306
/* Test that order of relations is preserved if some relations are deleted. */
307
static void
308
test_delete_ordering(void)
309
{
310
profile_t p;
311
const char *names[] = { "test section 1", "testkey", NULL };
312
char **values;
313
314
check(profile_init_path("test2.ini", &p));
315
check(profile_add_relation(p, names, "1"));
316
check(profile_add_relation(p, names, "2"));
317
check(profile_add_relation(p, names, "3"));
318
check(profile_update_relation(p, names, "2", NULL));
319
check(profile_add_relation(p, names, "4"));
320
check(profile_get_values(p, names, &values));
321
assert(strcmp(values[0], "1") == 0);
322
assert(strcmp(values[1], "3") == 0);
323
assert(strcmp(values[2], "4") == 0);
324
assert(values[3] == NULL);
325
profile_free_list(values);
326
profile_abandon(p);
327
}
328
329
/* Regression test for #8431 (profile_flush_to_file erroneously changes flag
330
* state on source object) */
331
static void
332
test_flush_to_file(void)
333
{
334
profile_t p;
335
336
/* Flush a profile object to a file without making any changes, so that the
337
* source object is still within g_shared_trees. */
338
check(profile_init_path("test2.ini", &p));
339
unlink("test3.ini");
340
check(profile_flush_to_file(p, "test3.ini"));
341
profile_release(p);
342
343
/* Check for a dangling reference in g_shared_trees by creating another
344
* profile object. */
345
profile_init_path("test2.ini", &p);
346
profile_release(p);
347
}
348
349
/* Regression test for #7863 (multiply-specified subsections should
350
* be merged) */
351
static void
352
test_merge_subsections(void)
353
{
354
profile_t p;
355
const char *n1[] = { "test section 2", "child_section2", "child", NULL };
356
const char *n2[] = { "test section 2", "child_section2", "chores", NULL };
357
char **values;
358
359
check(profile_init_path("test2.ini", &p));
360
361
check(profile_get_values(p, n1, &values));
362
assert(strcmp(values[0], "slick") == 0);
363
assert(strcmp(values[1], "harry") == 0);
364
assert(strcmp(values[2], "john\tb ") == 0);
365
assert(strcmp(values[3], "ron") == 0);
366
assert(values[4] == NULL);
367
profile_free_list(values);
368
369
check(profile_get_values(p, n2, &values));
370
assert(strcmp(values[0], "cleaning") == 0 && values[1] == NULL);
371
profile_free_list(values);
372
373
profile_release(p);
374
}
375
376
/* Regression test for #9110 (null dereference when modifying an empty
377
* profile), and various other operations on an initially empty profile. */
378
static void
379
test_empty(void)
380
{
381
profile_t p, p2;
382
const char *n1[] = { "section", NULL };
383
const char *n2[] = { "section", "var", NULL };
384
char **values;
385
386
check(profile_init(NULL, &p));
387
check(profile_add_relation(p, n1, NULL));
388
check(profile_add_relation(p, n2, "value"));
389
check(profile_flush(p)); /* should succeed but do nothing */
390
check(profile_get_values(p, n2, &values));
391
assert(strcmp(values[0], "value") == 0 && values[1] == NULL);
392
profile_free_list(values);
393
394
check(profile_copy(p, &p2));
395
check(profile_get_values(p2, n2, &values));
396
assert(strcmp(values[0], "value") == 0 && values[1] == NULL);
397
profile_free_list(values);
398
profile_release(p2);
399
400
profile_flush_to_file(p, "test3.ini");
401
profile_release(p);
402
403
profile_init_path("test3.ini", &p);
404
check(profile_get_values(p, n2, &values));
405
assert(strcmp(values[0], "value") == 0 && values[1] == NULL);
406
profile_free_list(values);
407
profile_release(p);
408
}
409
410
int
411
main(void)
412
{
413
test_iterate();
414
test_shared();
415
test_clear();
416
test_include();
417
test_independence();
418
test_delete_section();
419
test_delete_clear_relation();
420
test_delete_ordering();
421
test_flush_to_file();
422
test_merge_subsections();
423
test_empty();
424
}
425
426