Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/util/profile/prof_get.c
34879 views
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
{
41
list->num = 0;
42
list->max = 10;
43
list->list = malloc(list->max * sizeof(char *));
44
if (list->list == 0)
45
return ENOMEM;
46
list->list[0] = 0;
47
return 0;
48
}
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
{
56
char **cp;
57
58
if (list == 0)
59
return;
60
61
if (ret_list) {
62
*ret_list = list->list;
63
return;
64
} else {
65
for (cp = list->list; cp && *cp; cp++)
66
free(*cp);
67
free(list->list);
68
}
69
list->num = list->max = 0;
70
list->list = 0;
71
}
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
{
78
char *newstr, **newlist;
79
unsigned int newmax;
80
81
if (list->num+1 >= list->max) {
82
newmax = list->max + 10;
83
newlist = realloc(list->list, newmax * sizeof(char *));
84
if (newlist == 0)
85
return ENOMEM;
86
list->max = newmax;
87
list->list = newlist;
88
}
89
newstr = strdup(str);
90
if (newstr == 0)
91
return ENOMEM;
92
93
list->list[list->num++] = newstr;
94
list->list[list->num] = 0;
95
return 0;
96
}
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
{
103
char **cpp;
104
105
if (!list->list)
106
return 0;
107
108
for (cpp = list->list; *cpp; cpp++) {
109
if (!strcmp(*cpp, str))
110
return 1;
111
}
112
return 0;
113
}
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
{
121
char **cp;
122
123
if (list == 0)
124
return;
125
126
for (cp = list; *cp; cp++)
127
free(*cp);
128
free(list);
129
}
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
{
135
errcode_t retval;
136
char **vtvalues, **val;
137
struct profile_string_list values;
138
139
retval = profile->vt->get_values(profile->cbdata, names, &vtvalues);
140
if (retval)
141
return retval;
142
143
/* Copy the result into memory we can free. */
144
retval = init_list(&values);
145
if (retval == 0) {
146
for (val = vtvalues; *val; val++)
147
add_to_list(&values, *val);
148
end_list(&values, ret_values);
149
}
150
151
profile->vt->free_values(profile->cbdata, vtvalues);
152
return retval;
153
}
154
155
errcode_t KRB5_CALLCONV
156
profile_get_values(profile_t profile, const char *const *names,
157
char ***ret_values)
158
{
159
errcode_t retval;
160
void *state = NULL;
161
char *value;
162
struct profile_string_list values;
163
164
*ret_values = NULL;
165
if (!profile)
166
return PROF_NO_PROFILE;
167
if (profile->vt)
168
return get_values_vt(profile, names, ret_values);
169
170
if ((retval = profile_node_iterator_create(profile, names,
171
PROFILE_ITER_RELATIONS_ONLY,
172
&state)))
173
return retval;
174
175
retval = init_list(&values);
176
if (retval)
177
goto cleanup;
178
179
do {
180
if ((retval = profile_node_iterator(&state, 0, 0, &value)))
181
goto cleanup;
182
if (value)
183
add_to_list(&values, value);
184
} while (state);
185
186
if (values.num == 0) {
187
retval = PROF_NO_RELATION;
188
goto cleanup;
189
}
190
191
cleanup:
192
end_list(&values, retval ? NULL : ret_values);
193
profile_node_iterator_free(&state);
194
return retval;
195
}
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
{
202
errcode_t retval;
203
char **vtvalues;
204
205
retval = profile->vt->get_values(profile->cbdata, names, &vtvalues);
206
if (retval)
207
return retval;
208
*ret_value = strdup(*vtvalues);
209
if (*ret_value == NULL)
210
retval = ENOMEM;
211
profile->vt->free_values(profile->cbdata, vtvalues);
212
return retval;
213
}
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
{
222
errcode_t retval;
223
void *state;
224
char *value;
225
226
*ret_value = NULL;
227
if (!profile)
228
return PROF_NO_PROFILE;
229
if (profile->vt)
230
return get_value_vt(profile, names, ret_value);
231
232
retval = profile_iterator_create(profile, names,
233
PROFILE_ITER_RELATIONS_ONLY, &state);
234
if (retval)
235
return retval;
236
237
retval = profile_iterator(&state, NULL, &value);
238
if (retval)
239
goto cleanup;
240
241
if (value)
242
*ret_value = value;
243
else
244
retval = PROF_NO_RELATION;
245
246
cleanup:
247
profile_iterator_free(&state);
248
return retval;
249
}
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
{
256
char *value;
257
errcode_t retval;
258
const char *names[4];
259
260
if (profile) {
261
names[0] = name;
262
names[1] = subname;
263
names[2] = subsubname;
264
names[3] = 0;
265
retval = profile_get_value(profile, names, &value);
266
if (retval == 0) {
267
*ret_string = value;
268
return 0;
269
} else if (retval != PROF_NO_SECTION && retval != PROF_NO_RELATION)
270
return retval;
271
}
272
273
if (def_val) {
274
*ret_string = strdup(def_val);
275
if (*ret_string == NULL)
276
return ENOMEM;
277
} else
278
*ret_string = NULL;
279
return 0;
280
}
281
282
static errcode_t
283
parse_int(const char *value, int *ret_int)
284
{
285
char *end_value;
286
long ret_long;
287
288
if (value[0] == 0)
289
/* Empty string is no good. */
290
return PROF_BAD_INTEGER;
291
errno = 0;
292
ret_long = strtol(value, &end_value, 10);
293
294
/* Overflow or underflow. */
295
if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0)
296
return PROF_BAD_INTEGER;
297
/* Value outside "int" range. */
298
if ((long) (int) ret_long != ret_long)
299
return PROF_BAD_INTEGER;
300
/* Garbage in string. */
301
if (end_value != value + strlen (value))
302
return PROF_BAD_INTEGER;
303
304
*ret_int = ret_long;
305
return 0;
306
}
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
{
312
char *value;
313
errcode_t retval;
314
const char *names[4];
315
316
*ret_int = def_val;
317
if (profile == 0)
318
return 0;
319
320
names[0] = name;
321
names[1] = subname;
322
names[2] = subsubname;
323
names[3] = 0;
324
retval = profile_get_value(profile, names, &value);
325
if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
326
*ret_int = def_val;
327
return 0;
328
} else if (retval)
329
return retval;
330
331
retval = parse_int(value, ret_int);
332
free(value);
333
return retval;
334
}
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
{
349
const char *const *p;
350
351
if (ret_boolean == NULL)
352
return PROF_EINVAL;
353
354
for(p=conf_yes; *p; p++) {
355
if (!strcasecmp(*p,s)) {
356
*ret_boolean = 1;
357
return 0;
358
}
359
}
360
361
for(p=conf_no; *p; p++) {
362
if (!strcasecmp(*p,s)) {
363
*ret_boolean = 0;
364
return 0;
365
}
366
}
367
368
return PROF_BAD_BOOLEAN;
369
}
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
{
375
char *value;
376
errcode_t retval;
377
const char *names[4];
378
379
if (profile == 0) {
380
*ret_boolean = def_val;
381
return 0;
382
}
383
384
names[0] = name;
385
names[1] = subname;
386
names[2] = subsubname;
387
names[3] = 0;
388
retval = profile_get_value(profile, names, &value);
389
if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
390
*ret_boolean = def_val;
391
return 0;
392
} else if (retval)
393
return retval;
394
395
retval = profile_parse_boolean(value, ret_boolean);
396
free(value);
397
return retval;
398
}
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
{
408
errcode_t retval;
409
void *state;
410
char *name;
411
struct profile_string_list values;
412
413
if ((retval = profile_iterator_create(profile, names,
414
PROFILE_ITER_LIST_SECTION |
415
PROFILE_ITER_SECTIONS_ONLY,
416
&state)))
417
return retval;
418
419
if ((retval = init_list(&values)))
420
return retval;
421
422
do {
423
if ((retval = profile_iterator(&state, &name, NULL)))
424
goto cleanup;
425
if (name)
426
add_to_list(&values, name);
427
free(name);
428
} while (state);
429
430
end_list(&values, ret_names);
431
return 0;
432
433
cleanup:
434
end_list(&values, 0);
435
return retval;
436
}
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
{
446
errcode_t retval;
447
void *state;
448
char *name;
449
struct profile_string_list values;
450
451
if ((retval = profile_iterator_create(profile, names,
452
PROFILE_ITER_LIST_SECTION |
453
PROFILE_ITER_RELATIONS_ONLY,
454
&state)))
455
return retval;
456
457
if ((retval = init_list(&values)))
458
return retval;
459
460
do {
461
if ((retval = profile_iterator(&state, &name, NULL)))
462
goto cleanup;
463
if (name && !is_list_member(&values, name))
464
add_to_list(&values, name);
465
free(name);
466
} while (state);
467
468
end_list(&values, ret_names);
469
return 0;
470
471
cleanup:
472
end_list(&values, 0);
473
return retval;
474
}
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
{
486
struct profile_iterator *iter;
487
errcode_t retval;
488
489
*ret_iter = NULL;
490
if (!profile)
491
return PROF_NO_PROFILE;
492
493
iter = malloc(sizeof(*iter));
494
if (iter == NULL)
495
return ENOMEM;
496
iter->magic = PROF_MAGIC_ITERATOR;
497
iter->profile = profile;
498
499
/* Create the underlying iterator representation using the vtable or the
500
* built-in node iterator. */
501
if (profile->vt) {
502
if (!profile->vt->iterator_create)
503
retval = PROF_UNSUPPORTED;
504
else
505
retval = profile->vt->iterator_create(profile->cbdata, names,
506
flags, &iter->idata);
507
} else {
508
retval = profile_node_iterator_create(profile, names, flags,
509
&iter->idata);
510
}
511
if (retval) {
512
free(iter);
513
return retval;
514
}
515
516
*ret_iter = iter;
517
return 0;
518
}
519
520
void KRB5_CALLCONV
521
profile_iterator_free(void **iter_p)
522
{
523
struct profile_iterator *iter;
524
profile_t profile;
525
526
if (!iter_p)
527
return;
528
iter = *iter_p;
529
if (!iter || iter->magic != PROF_MAGIC_ITERATOR)
530
return;
531
profile = iter->profile;
532
if (profile->vt)
533
profile->vt->iterator_free(profile->cbdata, iter->idata);
534
else
535
profile_node_iterator_free(&iter->idata);
536
free(iter);
537
*iter_p = NULL;
538
}
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
{
546
char *name_copy = NULL, *value_copy = NULL;
547
548
if (ret_name && name) {
549
name_copy = strdup(name);
550
if (name_copy == NULL)
551
goto oom;
552
}
553
if (ret_value && value) {
554
value_copy = strdup(value);
555
if (value_copy == NULL)
556
goto oom;
557
}
558
if (ret_name)
559
*ret_name = name_copy;
560
if (ret_value)
561
*ret_value = value_copy;
562
return 0;
563
oom:
564
free(name_copy);
565
free(value_copy);
566
return ENOMEM;
567
}
568
569
errcode_t KRB5_CALLCONV
570
profile_iterator(void **iter_p, char **ret_name, char **ret_value)
571
{
572
char *name, *value;
573
errcode_t retval;
574
struct profile_iterator *iter = *iter_p;
575
profile_t profile;
576
577
if (ret_name)
578
*ret_name = NULL;
579
if (ret_value)
580
*ret_value = NULL;
581
if (iter == NULL || iter->magic != PROF_MAGIC_ITERATOR)
582
return PROF_MAGIC_ITERATOR;
583
profile = iter->profile;
584
585
if (profile->vt) {
586
retval = profile->vt->iterator(profile->cbdata, iter->idata, &name,
587
&value);
588
if (retval)
589
return retval;
590
if (name == NULL) {
591
profile->vt->iterator_free(profile->cbdata, iter->idata);
592
free(iter);
593
*iter_p = NULL;
594
}
595
retval = set_results(name, value, ret_name, ret_value);
596
if (name)
597
profile->vt->free_string(profile->cbdata, name);
598
if (value)
599
profile->vt->free_string(profile->cbdata, value);
600
return retval;
601
}
602
603
retval = profile_node_iterator(&iter->idata, 0, &name, &value);
604
if (iter->idata == NULL) {
605
free(iter);
606
*iter_p = NULL;
607
}
608
if (retval)
609
return retval;
610
return set_results(name, value, ret_name, ret_value);
611
}
612
613
void KRB5_CALLCONV
614
profile_release_string(char *str)
615
{
616
free(str);
617
}
618
619