Coverage Report

Created: 2025-08-26 06:18

/src/krb5/src/util/profile/prof_get.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/*
3
 * prof_get.c --- routines that expose the public interfaces for
4
 *      querying items from the profile.
5
 *
6
 */
7
8
#include "prof_int.h"
9
#include <stdio.h>
10
#include <string.h>
11
#ifdef HAVE_STDLIB_H
12
#include <stdlib.h>
13
#endif
14
#include <errno.h>
15
#include <limits.h>
16
17
/*
18
 * These functions --- init_list(), end_list(), and add_to_list() are
19
 * internal functions used to build up a null-terminated char ** list
20
 * of strings to be returned by functions like profile_get_values.
21
 *
22
 * The profile_string_list structure is used for internal booking
23
 * purposes to build up the list, which is returned in *ret_list by
24
 * the end_list() function.
25
 *
26
 * The publicly exported interface for freeing char** list is
27
 * profile_free_list().
28
 */
29
30
struct profile_string_list {
31
    char    **list;
32
    unsigned int    num;
33
    unsigned int    max;
34
};
35
36
/*
37
 * Initialize the string list abstraction.
38
 */
39
static errcode_t init_list(struct profile_string_list *list)
40
10.1k
{
41
10.1k
    list->num = 0;
42
10.1k
    list->max = 10;
43
10.1k
    list->list = malloc(list->max * sizeof(char *));
44
10.1k
    if (list->list == 0)
45
0
        return ENOMEM;
46
10.1k
    list->list[0] = 0;
47
10.1k
    return 0;
48
10.1k
}
49
50
/*
51
 * Free any memory left over in the string abstraction, returning the
52
 * built up list in *ret_list if it is non-null.
53
 */
54
static void end_list(struct profile_string_list *list, char ***ret_list)
55
10.1k
{
56
10.1k
    char    **cp;
57
58
10.1k
    if (list == 0)
59
0
        return;
60
61
10.1k
    if (ret_list) {
62
0
        *ret_list = list->list;
63
0
        return;
64
10.1k
    } else {
65
10.1k
        for (cp = list->list; cp && *cp; cp++)
66
0
            free(*cp);
67
10.1k
        free(list->list);
68
10.1k
    }
69
10.1k
    list->num = list->max = 0;
70
10.1k
    list->list = 0;
71
10.1k
}
72
73
/*
74
 * Add a string to the list.
75
 */
76
static errcode_t add_to_list(struct profile_string_list *list, const char *str)
77
0
{
78
0
    char    *newstr, **newlist;
79
0
    unsigned int    newmax;
80
81
0
    if (list->num+1 >= list->max) {
82
0
        newmax = list->max + 10;
83
0
        newlist = realloc(list->list, newmax * sizeof(char *));
84
0
        if (newlist == 0)
85
0
            return ENOMEM;
86
0
        list->max = newmax;
87
0
        list->list = newlist;
88
0
    }
89
0
    newstr = strdup(str);
90
0
    if (newstr == 0)
91
0
        return ENOMEM;
92
93
0
    list->list[list->num++] = newstr;
94
0
    list->list[list->num] = 0;
95
0
    return 0;
96
0
}
97
98
/*
99
 * Return TRUE if the string is already a member of the list.
100
 */
101
static int is_list_member(struct profile_string_list *list, const char *str)
102
0
{
103
0
    char **cpp;
104
105
0
    if (!list->list)
106
0
        return 0;
107
108
0
    for (cpp = list->list; *cpp; cpp++) {
109
0
        if (!strcmp(*cpp, str))
110
0
            return 1;
111
0
    }
112
0
    return 0;
113
0
}
114
115
/*
116
 * This function frees a null-terminated list as returned by
117
 * profile_get_values.
118
 */
119
void KRB5_CALLCONV profile_free_list(char **list)
120
10.1k
{
121
10.1k
    char        **cp;
122
123
10.1k
    if (list == 0)
124
10.1k
        return;
125
126
0
    for (cp = list; *cp; cp++)
127
0
        free(*cp);
128
0
    free(list);
129
0
}
130
131
/* Look up a relation in a vtable profile. */
132
static errcode_t
133
get_values_vt(profile_t profile, const char *const *names, char ***ret_values)
134
0
{
135
0
    errcode_t               retval;
136
0
    char                    **vtvalues, **val;
137
0
    struct profile_string_list values;
138
139
0
    retval = profile->vt->get_values(profile->cbdata, names, &vtvalues);
140
0
    if (retval)
141
0
        return retval;
142
143
    /* Copy the result into memory we can free. */
144
0
    retval = init_list(&values);
145
0
    if (retval == 0) {
146
0
        for (val = vtvalues; *val; val++)
147
0
            add_to_list(&values, *val);
148
0
        end_list(&values, ret_values);
149
0
    }
150
151
0
    profile->vt->free_values(profile->cbdata, vtvalues);
152
0
    return retval;
153
0
}
154
155
errcode_t KRB5_CALLCONV
156
profile_get_values(profile_t profile, const char *const *names,
157
                   char ***ret_values)
158
10.1k
{
159
10.1k
    errcode_t               retval;
160
10.1k
    void                    *state = NULL;
161
10.1k
    char                    *value;
162
10.1k
    struct profile_string_list values;
163
164
10.1k
    *ret_values = NULL;
165
10.1k
    if (!profile)
166
0
        return PROF_NO_PROFILE;
167
10.1k
    if (profile->vt)
168
0
        return get_values_vt(profile, names, ret_values);
169
170
10.1k
    if ((retval = profile_node_iterator_create(profile, names,
171
10.1k
                                               PROFILE_ITER_RELATIONS_ONLY,
172
10.1k
                                               &state)))
173
0
        return retval;
174
175
10.1k
    retval = init_list(&values);
176
10.1k
    if (retval)
177
0
        goto cleanup;
178
179
10.1k
    do {
180
10.1k
        if ((retval = profile_node_iterator(&state, 0, 0, &value)))
181
0
            goto cleanup;
182
10.1k
        if (value)
183
0
            add_to_list(&values, value);
184
10.1k
    } while (state);
185
186
10.1k
    if (values.num == 0) {
187
10.1k
        retval = PROF_NO_RELATION;
188
10.1k
        goto cleanup;
189
10.1k
    }
190
191
10.1k
cleanup:
192
10.1k
    end_list(&values, retval ? NULL : ret_values);
193
10.1k
    profile_node_iterator_free(&state);
194
10.1k
    return retval;
195
10.1k
}
196
197
/* Look up a relation in a vtable profile and return the first value in the
198
 * result. */
199
static errcode_t
200
get_value_vt(profile_t profile, const char *const *names, char **ret_value)
201
0
{
202
0
    errcode_t               retval;
203
0
    char                    **vtvalues;
204
205
0
    retval = profile->vt->get_values(profile->cbdata, names, &vtvalues);
206
0
    if (retval)
207
0
        return retval;
208
0
    *ret_value = strdup(*vtvalues);
209
0
    if (*ret_value == NULL)
210
0
        retval = ENOMEM;
211
0
    profile->vt->free_values(profile->cbdata, vtvalues);
212
0
    return retval;
213
0
}
214
215
/*
216
 * This function only gets the first value from the file; it is a
217
 * helper function for profile_get_string, profile_get_integer, etc.
218
 */
219
errcode_t profile_get_value(profile_t profile, const char **names,
220
                            char **ret_value)
221
204k
{
222
204k
    errcode_t               retval;
223
204k
    void                    *state;
224
204k
    char                    *value;
225
226
204k
    *ret_value = NULL;
227
204k
    if (!profile)
228
0
        return PROF_NO_PROFILE;
229
204k
    if (profile->vt)
230
0
        return get_value_vt(profile, names, ret_value);
231
232
204k
    retval = profile_iterator_create(profile, names,
233
204k
                                     PROFILE_ITER_RELATIONS_ONLY, &state);
234
204k
    if (retval)
235
0
        return retval;
236
237
204k
    retval = profile_iterator(&state, NULL, &value);
238
204k
    if (retval)
239
0
        goto cleanup;
240
241
204k
    if (value)
242
0
        *ret_value = value;
243
204k
    else
244
204k
        retval = PROF_NO_RELATION;
245
246
204k
cleanup:
247
204k
    profile_iterator_free(&state);
248
204k
    return retval;
249
204k
}
250
251
errcode_t KRB5_CALLCONV
252
profile_get_string(profile_t profile, const char *name, const char *subname,
253
                   const char *subsubname, const char *def_val,
254
                   char **ret_string)
255
62.5k
{
256
62.5k
    char            *value;
257
62.5k
    errcode_t       retval;
258
62.5k
    const char      *names[4];
259
260
62.5k
    if (profile) {
261
62.5k
        names[0] = name;
262
62.5k
        names[1] = subname;
263
62.5k
        names[2] = subsubname;
264
62.5k
        names[3] = 0;
265
62.5k
        retval = profile_get_value(profile, names, &value);
266
62.5k
        if (retval == 0) {
267
0
            *ret_string = value;
268
0
            return 0;
269
62.5k
        } else if (retval != PROF_NO_SECTION && retval != PROF_NO_RELATION)
270
0
            return retval;
271
62.5k
    }
272
273
62.5k
    if (def_val) {
274
14.1k
        *ret_string = strdup(def_val);
275
14.1k
        if (*ret_string == NULL)
276
0
            return ENOMEM;
277
14.1k
    } else
278
48.4k
        *ret_string = NULL;
279
62.5k
    return 0;
280
62.5k
}
281
282
static errcode_t
283
parse_int(const char *value, int *ret_int)
284
0
{
285
0
    char            *end_value;
286
0
    long            ret_long;
287
288
0
    if (value[0] == 0)
289
        /* Empty string is no good.  */
290
0
        return PROF_BAD_INTEGER;
291
0
    errno = 0;
292
0
    ret_long = strtol(value, &end_value, 10);
293
294
    /* Overflow or underflow.  */
295
0
    if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0)
296
0
        return PROF_BAD_INTEGER;
297
    /* Value outside "int" range.  */
298
0
    if ((long) (int) ret_long != ret_long)
299
0
        return PROF_BAD_INTEGER;
300
    /* Garbage in string.  */
301
0
    if (end_value != value + strlen (value))
302
0
        return PROF_BAD_INTEGER;
303
304
0
    *ret_int = ret_long;
305
0
    return 0;
306
0
}
307
308
errcode_t KRB5_CALLCONV
309
profile_get_integer(profile_t profile, const char *name, const char *subname,
310
                    const char *subsubname, int def_val, int *ret_int)
311
56.6k
{
312
56.6k
    char            *value;
313
56.6k
    errcode_t       retval;
314
56.6k
    const char      *names[4];
315
316
56.6k
    *ret_int = def_val;
317
56.6k
    if (profile == 0)
318
0
        return 0;
319
320
56.6k
    names[0] = name;
321
56.6k
    names[1] = subname;
322
56.6k
    names[2] = subsubname;
323
56.6k
    names[3] = 0;
324
56.6k
    retval = profile_get_value(profile, names, &value);
325
56.6k
    if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
326
56.6k
        *ret_int = def_val;
327
56.6k
        return 0;
328
56.6k
    } else if (retval)
329
0
        return retval;
330
331
0
    retval = parse_int(value, ret_int);
332
0
    free(value);
333
0
    return retval;
334
56.6k
}
335
336
static const char *const conf_yes[] = {
337
    "y", "yes", "true", "t", "1", "on",
338
    0,
339
};
340
341
static const char *const conf_no[] = {
342
    "n", "no", "false", "nil", "0", "off",
343
    0,
344
};
345
346
static errcode_t
347
profile_parse_boolean(const char *s, int *ret_boolean)
348
0
{
349
0
    const char *const *p;
350
351
0
    if (ret_boolean == NULL)
352
0
        return PROF_EINVAL;
353
354
0
    for(p=conf_yes; *p; p++) {
355
0
        if (!strcasecmp(*p,s)) {
356
0
            *ret_boolean = 1;
357
0
            return 0;
358
0
        }
359
0
    }
360
361
0
    for(p=conf_no; *p; p++) {
362
0
        if (!strcasecmp(*p,s)) {
363
0
            *ret_boolean = 0;
364
0
            return 0;
365
0
        }
366
0
    }
367
368
0
    return PROF_BAD_BOOLEAN;
369
0
}
370
371
errcode_t KRB5_CALLCONV
372
profile_get_boolean(profile_t profile, const char *name, const char *subname,
373
                    const char *subsubname, int def_val, int *ret_boolean)
374
84.9k
{
375
84.9k
    char            *value;
376
84.9k
    errcode_t       retval;
377
84.9k
    const char      *names[4];
378
379
84.9k
    if (profile == 0) {
380
0
        *ret_boolean = def_val;
381
0
        return 0;
382
0
    }
383
384
84.9k
    names[0] = name;
385
84.9k
    names[1] = subname;
386
84.9k
    names[2] = subsubname;
387
84.9k
    names[3] = 0;
388
84.9k
    retval = profile_get_value(profile, names, &value);
389
84.9k
    if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
390
84.9k
        *ret_boolean = def_val;
391
84.9k
        return 0;
392
84.9k
    } else if (retval)
393
0
        return retval;
394
395
0
    retval = profile_parse_boolean(value, ret_boolean);
396
0
    free(value);
397
0
    return retval;
398
84.9k
}
399
400
/*
401
 * This function will return the list of the names of subections in the
402
 * under the specified section name.
403
 */
404
errcode_t KRB5_CALLCONV
405
profile_get_subsection_names(profile_t profile, const char **names,
406
                             char ***ret_names)
407
0
{
408
0
    errcode_t               retval;
409
0
    void                    *state;
410
0
    char                    *name;
411
0
    struct profile_string_list values;
412
413
0
    if ((retval = profile_iterator_create(profile, names,
414
0
                                          PROFILE_ITER_LIST_SECTION |
415
0
                                          PROFILE_ITER_SECTIONS_ONLY,
416
0
                                          &state)))
417
0
        return retval;
418
419
0
    if ((retval = init_list(&values)))
420
0
        return retval;
421
422
0
    do {
423
0
        if ((retval = profile_iterator(&state, &name, NULL)))
424
0
            goto cleanup;
425
0
        if (name)
426
0
            add_to_list(&values, name);
427
0
        free(name);
428
0
    } while (state);
429
430
0
    end_list(&values, ret_names);
431
0
    return 0;
432
433
0
cleanup:
434
0
    end_list(&values, 0);
435
0
    return retval;
436
0
}
437
438
/*
439
 * This function will return the list of the names of relations in the
440
 * under the specified section name.
441
 */
442
errcode_t KRB5_CALLCONV
443
profile_get_relation_names(profile_t profile, const char **names,
444
                           char ***ret_names)
445
0
{
446
0
    errcode_t               retval;
447
0
    void                    *state;
448
0
    char                    *name;
449
0
    struct profile_string_list values;
450
451
0
    if ((retval = profile_iterator_create(profile, names,
452
0
                                          PROFILE_ITER_LIST_SECTION |
453
0
                                          PROFILE_ITER_RELATIONS_ONLY,
454
0
                                          &state)))
455
0
        return retval;
456
457
0
    if ((retval = init_list(&values)))
458
0
        return retval;
459
460
0
    do {
461
0
        if ((retval = profile_iterator(&state, &name, NULL)))
462
0
            goto cleanup;
463
0
        if (name && !is_list_member(&values, name))
464
0
            add_to_list(&values, name);
465
0
        free(name);
466
0
    } while (state);
467
468
0
    end_list(&values, ret_names);
469
0
    return 0;
470
471
0
cleanup:
472
0
    end_list(&values, 0);
473
0
    return retval;
474
0
}
475
476
struct profile_iterator {
477
    prf_magic_t magic;
478
    profile_t profile;
479
    void *idata;
480
};
481
482
errcode_t KRB5_CALLCONV
483
profile_iterator_create(profile_t profile, const char *const *names, int flags,
484
                        void **ret_iter)
485
207k
{
486
207k
    struct profile_iterator *iter;
487
207k
    errcode_t retval;
488
489
207k
    *ret_iter = NULL;
490
207k
    if (!profile)
491
0
        return PROF_NO_PROFILE;
492
493
207k
    iter = malloc(sizeof(*iter));
494
207k
    if (iter == NULL)
495
0
        return ENOMEM;
496
207k
    iter->magic = PROF_MAGIC_ITERATOR;
497
207k
    iter->profile = profile;
498
499
    /* Create the underlying iterator representation using the vtable or the
500
     * built-in node iterator. */
501
207k
    if (profile->vt) {
502
0
        if (!profile->vt->iterator_create)
503
0
            retval = PROF_UNSUPPORTED;
504
0
        else
505
0
            retval = profile->vt->iterator_create(profile->cbdata, names,
506
0
                                                  flags, &iter->idata);
507
207k
    } else {
508
207k
        retval = profile_node_iterator_create(profile, names, flags,
509
207k
                                              &iter->idata);
510
207k
    }
511
207k
    if (retval) {
512
0
        free(iter);
513
0
        return retval;
514
0
    }
515
516
207k
    *ret_iter = iter;
517
207k
    return 0;
518
207k
}
519
520
void KRB5_CALLCONV
521
profile_iterator_free(void **iter_p)
522
204k
{
523
204k
    struct profile_iterator *iter;
524
204k
    profile_t profile;
525
526
204k
    if (!iter_p)
527
0
        return;
528
204k
    iter = *iter_p;
529
204k
    if (!iter || iter->magic != PROF_MAGIC_ITERATOR)
530
204k
        return;
531
0
    profile = iter->profile;
532
0
    if (profile->vt)
533
0
        profile->vt->iterator_free(profile->cbdata, iter->idata);
534
0
    else
535
0
        profile_node_iterator_free(&iter->idata);
536
0
    free(iter);
537
0
    *iter_p = NULL;
538
0
}
539
540
/* Make copies of name and value into *ret_name and *ret_value.  Handle null
541
 * values of any argument. */
542
static errcode_t
543
set_results(const char *name, const char *value, char **ret_name,
544
            char **ret_value)
545
207k
{
546
207k
    char *name_copy = NULL, *value_copy = NULL;
547
548
207k
    if (ret_name && name) {
549
0
        name_copy = strdup(name);
550
0
        if (name_copy == NULL)
551
0
            goto oom;
552
0
    }
553
207k
    if (ret_value && value) {
554
0
        value_copy = strdup(value);
555
0
        if (value_copy == NULL)
556
0
            goto oom;
557
0
    }
558
207k
    if (ret_name)
559
3.16k
        *ret_name = name_copy;
560
207k
    if (ret_value)
561
207k
        *ret_value = value_copy;
562
207k
    return 0;
563
0
oom:
564
0
    free(name_copy);
565
0
    free(value_copy);
566
0
    return ENOMEM;
567
207k
}
568
569
errcode_t KRB5_CALLCONV
570
profile_iterator(void **iter_p, char **ret_name, char **ret_value)
571
207k
{
572
207k
    char *name, *value;
573
207k
    errcode_t       retval;
574
207k
    struct profile_iterator *iter = *iter_p;
575
207k
    profile_t profile;
576
577
207k
    if (ret_name)
578
3.16k
        *ret_name = NULL;
579
207k
    if (ret_value)
580
207k
        *ret_value = NULL;
581
207k
    if (iter == NULL || iter->magic != PROF_MAGIC_ITERATOR)
582
0
        return PROF_MAGIC_ITERATOR;
583
207k
    profile = iter->profile;
584
585
207k
    if (profile->vt) {
586
0
        retval = profile->vt->iterator(profile->cbdata, iter->idata, &name,
587
0
                                       &value);
588
0
        if (retval)
589
0
            return retval;
590
0
        if (name == NULL) {
591
0
            profile->vt->iterator_free(profile->cbdata, iter->idata);
592
0
            free(iter);
593
0
            *iter_p = NULL;
594
0
        }
595
0
        retval = set_results(name, value, ret_name, ret_value);
596
0
        if (name)
597
0
            profile->vt->free_string(profile->cbdata, name);
598
0
        if (value)
599
0
            profile->vt->free_string(profile->cbdata, value);
600
0
        return retval;
601
0
    }
602
603
207k
    retval = profile_node_iterator(&iter->idata, 0, &name, &value);
604
207k
    if (iter->idata == NULL) {
605
207k
        free(iter);
606
207k
        *iter_p = NULL;
607
207k
    }
608
207k
    if (retval)
609
0
        return retval;
610
207k
    return set_results(name, value, ret_name, ret_value);
611
207k
}
612
613
void KRB5_CALLCONV
614
profile_release_string(char *str)
615
28.3k
{
616
28.3k
    free(str);
617
28.3k
}