1 /* $NetBSD: config_file.c,v 1.5 2023/06/19 21:41:44 christos Exp $ */
2
3 /*
4 * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * 3. Neither the name of the Institute nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #include "krb5_locl.h"
39
40 #ifdef __APPLE__
41 #include <CoreFoundation/CoreFoundation.h>
42 #endif
43
44 /* Gaah! I want a portable funopen */
45 struct fileptr {
46 const char *s;
47 FILE *f;
48 };
49
50 static char *
config_fgets(char * str,size_t len,struct fileptr * ptr)51 config_fgets(char *str, size_t len, struct fileptr *ptr)
52 {
53 /* XXX this is not correct, in that they don't do the same if the
54 line is longer than len */
55 if(ptr->f != NULL)
56 return fgets(str, len, ptr->f);
57 else {
58 /* this is almost strsep_copy */
59 const char *p;
60 ssize_t l;
61 if(*ptr->s == '\0')
62 return NULL;
63 p = ptr->s + strcspn(ptr->s, "\n");
64 if(*p == '\n')
65 p++;
66 l = min(len, (size_t)(p - ptr->s));
67 if(len > 0) {
68 memcpy(str, ptr->s, l);
69 str[l] = '\0';
70 }
71 ptr->s = p;
72 return str;
73 }
74 }
75
76 static krb5_error_code parse_section(char *p, krb5_config_section **s,
77 krb5_config_section **res,
78 const char **err_message);
79 static krb5_error_code parse_binding(struct fileptr *f, unsigned *lineno, char *p,
80 krb5_config_binding **b,
81 krb5_config_binding **parent,
82 const char **err_message);
83 static krb5_error_code parse_list(struct fileptr *f, unsigned *lineno,
84 krb5_config_binding **parent,
85 const char **err_message);
86
87 KRB5_LIB_FUNCTION krb5_config_section * KRB5_LIB_CALL
_krb5_config_get_entry(krb5_config_section ** parent,const char * name,int type)88 _krb5_config_get_entry(krb5_config_section **parent, const char *name, int type)
89 {
90 krb5_config_section **q;
91
92 for(q = parent; *q != NULL; q = &(*q)->next)
93 if(type == krb5_config_list &&
94 (unsigned)type == (*q)->type &&
95 strcmp(name, (*q)->name) == 0)
96 return *q;
97 *q = calloc(1, sizeof(**q));
98 if(*q == NULL)
99 return NULL;
100 (*q)->name = strdup(name);
101 (*q)->type = type;
102 if((*q)->name == NULL) {
103 free(*q);
104 *q = NULL;
105 return NULL;
106 }
107 return *q;
108 }
109
110 /*
111 * Parse a section:
112 *
113 * [section]
114 * foo = bar
115 * b = {
116 * a
117 * }
118 * ...
119 *
120 * starting at the line in `p', storing the resulting structure in
121 * `s' and hooking it into `parent'.
122 * Store the error message in `err_message'.
123 */
124
125 static krb5_error_code
parse_section(char * p,krb5_config_section ** s,krb5_config_section ** parent,const char ** err_message)126 parse_section(char *p, krb5_config_section **s, krb5_config_section **parent,
127 const char **err_message)
128 {
129 char *p1;
130 krb5_config_section *tmp;
131
132 p1 = strchr (p + 1, ']');
133 if (p1 == NULL) {
134 *err_message = "missing ]";
135 return KRB5_CONFIG_BADFORMAT;
136 }
137 *p1 = '\0';
138 tmp = _krb5_config_get_entry(parent, p + 1, krb5_config_list);
139 if(tmp == NULL) {
140 *err_message = "out of memory";
141 return KRB5_CONFIG_BADFORMAT;
142 }
143 *s = tmp;
144 return 0;
145 }
146
147 /*
148 * Parse a brace-enclosed list from `f', hooking in the structure at
149 * `parent'.
150 * Store the error message in `err_message'.
151 */
152
153 static krb5_error_code
parse_list(struct fileptr * f,unsigned * lineno,krb5_config_binding ** parent,const char ** err_message)154 parse_list(struct fileptr *f, unsigned *lineno, krb5_config_binding **parent,
155 const char **err_message)
156 {
157 char buf[KRB5_BUFSIZ];
158 krb5_error_code ret;
159 krb5_config_binding *b = NULL;
160 unsigned beg_lineno = *lineno;
161
162 while(config_fgets(buf, sizeof(buf), f) != NULL) {
163 char *p;
164
165 ++*lineno;
166 buf[strcspn(buf, "\r\n")] = '\0';
167 p = buf;
168 while(isspace((unsigned char)*p))
169 ++p;
170 if (*p == '#' || *p == ';' || *p == '\0')
171 continue;
172 while(isspace((unsigned char)*p))
173 ++p;
174 if (*p == '}')
175 return 0;
176 if (*p == '\0')
177 continue;
178 ret = parse_binding (f, lineno, p, &b, parent, err_message);
179 if (ret)
180 return ret;
181 }
182 *lineno = beg_lineno;
183 *err_message = "unclosed {";
184 return KRB5_CONFIG_BADFORMAT;
185 }
186
187 /*
188 *
189 */
190
191 static krb5_error_code
parse_binding(struct fileptr * f,unsigned * lineno,char * p,krb5_config_binding ** b,krb5_config_binding ** parent,const char ** err_message)192 parse_binding(struct fileptr *f, unsigned *lineno, char *p,
193 krb5_config_binding **b, krb5_config_binding **parent,
194 const char **err_message)
195 {
196 krb5_config_binding *tmp;
197 char *p1, *p2;
198 krb5_error_code ret = 0;
199
200 p1 = p;
201 while (*p && *p != '=' && !isspace((unsigned char)*p))
202 ++p;
203 if (*p == '\0') {
204 *err_message = "missing =";
205 return KRB5_CONFIG_BADFORMAT;
206 }
207 p2 = p;
208 while (isspace((unsigned char)*p))
209 ++p;
210 if (*p != '=') {
211 *err_message = "missing =";
212 return KRB5_CONFIG_BADFORMAT;
213 }
214 ++p;
215 while(isspace((unsigned char)*p))
216 ++p;
217 *p2 = '\0';
218 if (*p == '{') {
219 tmp = _krb5_config_get_entry(parent, p1, krb5_config_list);
220 if (tmp == NULL) {
221 *err_message = "out of memory";
222 return KRB5_CONFIG_BADFORMAT;
223 }
224 ret = parse_list (f, lineno, &tmp->u.list, err_message);
225 } else {
226 tmp = _krb5_config_get_entry(parent, p1, krb5_config_string);
227 if (tmp == NULL) {
228 *err_message = "out of memory";
229 return KRB5_CONFIG_BADFORMAT;
230 }
231 p1 = p;
232 p = p1 + strlen(p1);
233 while(p > p1 && isspace((unsigned char)*(p-1)))
234 --p;
235 *p = '\0';
236 tmp->u.string = strdup(p1);
237 }
238 *b = tmp;
239 return ret;
240 }
241
242 #if defined(__APPLE__)
243
244 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
245 #define HAVE_CFPROPERTYLISTCREATEWITHSTREAM 1
246 #endif
247
248 static char *
cfstring2cstring(CFStringRef string)249 cfstring2cstring(CFStringRef string)
250 {
251 CFIndex len;
252 char *str;
253
254 str = (char *) CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
255 if (str)
256 return strdup(str);
257
258 len = CFStringGetLength(string);
259 len = 1 + CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8);
260 str = malloc(len);
261 if (str == NULL)
262 return NULL;
263
264 if (!CFStringGetCString (string, str, len, kCFStringEncodingUTF8)) {
265 free (str);
266 return NULL;
267 }
268 return str;
269 }
270
271 static void
convert_content(const void * key,const void * value,void * context)272 convert_content(const void *key, const void *value, void *context)
273 {
274 krb5_config_section *tmp, **parent = context;
275 char *k;
276
277 if (CFGetTypeID(key) != CFStringGetTypeID())
278 return;
279
280 k = cfstring2cstring(key);
281 if (k == NULL)
282 return;
283
284 if (CFGetTypeID(value) == CFStringGetTypeID()) {
285 tmp = _krb5_config_get_entry(parent, k, krb5_config_string);
286 tmp->u.string = cfstring2cstring(value);
287 } else if (CFGetTypeID(value) == CFDictionaryGetTypeID()) {
288 tmp = _krb5_config_get_entry(parent, k, krb5_config_list);
289 CFDictionaryApplyFunction(value, convert_content, &tmp->u.list);
290 } else {
291 /* log */
292 }
293 free(k);
294 }
295
296 static krb5_error_code
parse_plist_config(krb5_context context,const char * path,krb5_config_section ** parent)297 parse_plist_config(krb5_context context, const char *path, krb5_config_section **parent)
298 {
299 CFReadStreamRef s;
300 CFDictionaryRef d;
301 CFURLRef url;
302
303 url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)path, strlen(path), FALSE);
304 if (url == NULL) {
305 krb5_clear_error_message(context);
306 return ENOMEM;
307 }
308
309 s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
310 CFRelease(url);
311 if (s == NULL) {
312 krb5_clear_error_message(context);
313 return ENOMEM;
314 }
315
316 if (!CFReadStreamOpen(s)) {
317 CFRelease(s);
318 krb5_clear_error_message(context);
319 return ENOENT;
320 }
321
322 #ifdef HAVE_CFPROPERTYLISTCREATEWITHSTREAM
323 d = (CFDictionaryRef)CFPropertyListCreateWithStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL);
324 #else
325 d = (CFDictionaryRef)CFPropertyListCreateFromStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL);
326 #endif
327 CFRelease(s);
328 if (d == NULL) {
329 krb5_clear_error_message(context);
330 return ENOENT;
331 }
332
333 CFDictionaryApplyFunction(d, convert_content, parent);
334 CFRelease(d);
335
336 return 0;
337 }
338
339 #endif
340
341
342 /*
343 * Parse the config file `fname', generating the structures into `res'
344 * returning error messages in `err_message'
345 */
346
347 static krb5_error_code
krb5_config_parse_debug(struct fileptr * f,krb5_config_section ** res,unsigned * lineno,const char ** err_message)348 krb5_config_parse_debug (struct fileptr *f,
349 krb5_config_section **res,
350 unsigned *lineno,
351 const char **err_message)
352 {
353 krb5_config_section *s = NULL;
354 krb5_config_binding *b = NULL;
355 char buf[KRB5_BUFSIZ];
356 krb5_error_code ret;
357
358 *lineno = 0;
359 *err_message = "";
360
361 while (config_fgets(buf, sizeof(buf), f) != NULL) {
362 char *p;
363
364 ++*lineno;
365 buf[strcspn(buf, "\r\n")] = '\0';
366 p = buf;
367 while(isspace((unsigned char)*p))
368 ++p;
369 if (*p == '#' || *p == ';')
370 continue;
371 if (*p == '[') {
372 ret = parse_section(p, &s, res, err_message);
373 if (ret)
374 return ret;
375 b = NULL;
376 } else if (*p == '}') {
377 *err_message = "unmatched }";
378 return KRB5_CONFIG_BADFORMAT;
379 } else if(*p != '\0') {
380 if (s == NULL) {
381 *err_message = "binding before section";
382 return KRB5_CONFIG_BADFORMAT;
383 }
384 ret = parse_binding(f, lineno, p, &b, &s->u.list, err_message);
385 if (ret)
386 return ret;
387 }
388 }
389 return 0;
390 }
391
392 static int
is_plist_file(const char * fname)393 is_plist_file(const char *fname)
394 {
395 size_t len = strlen(fname);
396 char suffix[] = ".plist";
397 if (len < sizeof(suffix))
398 return 0;
399 if (strcasecmp(&fname[len - (sizeof(suffix) - 1)], suffix) != 0)
400 return 0;
401 return 1;
402 }
403
404 /**
405 * Parse a configuration file and add the result into res. This
406 * interface can be used to parse several configuration files into one
407 * resulting krb5_config_section by calling it repeatably.
408 *
409 * @param context a Kerberos 5 context.
410 * @param fname a file name to a Kerberos configuration file
411 * @param res the returned result, must be free with krb5_free_config_files().
412 * @return Return an error code or 0, see krb5_get_error_message().
413 *
414 * @ingroup krb5_support
415 */
416
417 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_config_parse_file_multi(krb5_context context,const char * fname,krb5_config_section ** res)418 krb5_config_parse_file_multi (krb5_context context,
419 const char *fname,
420 krb5_config_section **res)
421 {
422 const char *str;
423 char *newfname = NULL;
424 unsigned lineno = 0;
425 krb5_error_code ret;
426 struct fileptr f;
427
428 /**
429 * If the fname starts with "~/" parse configuration file in the
430 * current users home directory. The behavior can be disabled and
431 * enabled by calling krb5_set_home_dir_access().
432 */
433 if (ISTILDE(fname[0]) && ISPATHSEP(fname[1])) {
434 #ifndef KRB5_USE_PATH_TOKENS
435 const char *home = NULL;
436 struct passwd pw, *pwd = NULL;
437 char pwbuf[2048];
438
439 if (!_krb5_homedir_access(context)) {
440 krb5_set_error_message(context, EPERM,
441 "Access to home directory not allowed");
442 return EPERM;
443 }
444
445 if(!issuid())
446 home = getenv("HOME");
447
448 if (home == NULL) {
449 if (rk_getpwuid_r(getuid(), &pw, pwbuf, sizeof(pwbuf), &pwd) == 0)
450 home = pwd->pw_dir;
451 }
452 if (home) {
453 int aret;
454
455 aret = asprintf(&newfname, "%s%s", home, &fname[1]);
456 if (aret == -1 || newfname == NULL)
457 return krb5_enomem(context);
458 fname = newfname;
459 }
460 #else /* KRB5_USE_PATH_TOKENS */
461 if (asprintf(&newfname, "%%{USERCONFIG}%s", &fname[1]) < 0 ||
462 newfname == NULL)
463 return krb5_enomem(context);
464 fname = newfname;
465 #endif
466 }
467
468 if (is_plist_file(fname)) {
469 #ifdef __APPLE__
470 ret = parse_plist_config(context, fname, res);
471 if (ret) {
472 krb5_set_error_message(context, ret,
473 "Failed to parse plist %s", fname);
474 if (newfname)
475 free(newfname);
476 return ret;
477 }
478 #else
479 krb5_set_error_message(context, ENOENT,
480 "no support for plist configuration files");
481 return ENOENT;
482 #endif
483 } else {
484 #ifdef KRB5_USE_PATH_TOKENS
485 char * exp_fname = NULL;
486
487 ret = _krb5_expand_path_tokens(context, fname, 1, &exp_fname);
488 if (ret) {
489 if (newfname)
490 free(newfname);
491 return ret;
492 }
493
494 if (newfname)
495 free(newfname);
496 fname = newfname = exp_fname;
497 #endif
498
499 f.f = fopen(fname, "r");
500 f.s = NULL;
501 if(f.f == NULL) {
502 ret = errno;
503 krb5_set_error_message (context, ret, "open %s: %s",
504 fname, strerror(ret));
505 if (newfname)
506 free(newfname);
507 return ret;
508 }
509
510 ret = krb5_config_parse_debug (&f, res, &lineno, &str);
511 fclose(f.f);
512 if (ret) {
513 krb5_set_error_message (context, ret, "%s:%u: %s",
514 fname, lineno, str);
515 if (newfname)
516 free(newfname);
517 return ret;
518 }
519 }
520 return 0;
521 }
522
523 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_config_parse_file(krb5_context context,const char * fname,krb5_config_section ** res)524 krb5_config_parse_file (krb5_context context,
525 const char *fname,
526 krb5_config_section **res)
527 {
528 *res = NULL;
529 return krb5_config_parse_file_multi(context, fname, res);
530 }
531
532 static void
free_binding(krb5_context context,krb5_config_binding * b)533 free_binding (krb5_context context, krb5_config_binding *b)
534 {
535 krb5_config_binding *next_b;
536
537 while (b) {
538 free (b->name);
539 if (b->type == krb5_config_string)
540 free (b->u.string);
541 else if (b->type == krb5_config_list)
542 free_binding (context, b->u.list);
543 else
544 krb5_abortx(context, "unknown binding type (%d) in free_binding",
545 b->type);
546 next_b = b->next;
547 free (b);
548 b = next_b;
549 }
550 }
551
552 /**
553 * Free configuration file section, the result of
554 * krb5_config_parse_file() and krb5_config_parse_file_multi().
555 *
556 * @param context A Kerberos 5 context
557 * @param s the configuration section to free
558 *
559 * @return returns 0 on successes, otherwise an error code, see
560 * krb5_get_error_message()
561 *
562 * @ingroup krb5_support
563 */
564
565 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_config_file_free(krb5_context context,krb5_config_section * s)566 krb5_config_file_free (krb5_context context, krb5_config_section *s)
567 {
568 free_binding (context, s);
569 return 0;
570 }
571
572 #ifndef HEIMDAL_SMALLER
573
574 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_config_copy(krb5_context context,krb5_config_section * c,krb5_config_section ** head)575 _krb5_config_copy(krb5_context context,
576 krb5_config_section *c,
577 krb5_config_section **head)
578 {
579 krb5_config_binding *d, *previous = NULL;
580
581 *head = NULL;
582
583 while (c) {
584 d = calloc(1, sizeof(*d));
585
586 if (*head == NULL)
587 *head = d;
588
589 d->name = strdup(c->name);
590 d->type = c->type;
591 if (d->type == krb5_config_string)
592 d->u.string = strdup(c->u.string);
593 else if (d->type == krb5_config_list)
594 _krb5_config_copy (context, c->u.list, &d->u.list);
595 else
596 krb5_abortx(context,
597 "unknown binding type (%d) in krb5_config_copy",
598 d->type);
599 if (previous)
600 previous->next = d;
601
602 previous = d;
603 c = c->next;
604 }
605 return 0;
606 }
607
608 #endif /* HEIMDAL_SMALLER */
609
610 KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL
_krb5_config_get_next(krb5_context context,const krb5_config_section * c,const krb5_config_binding ** pointer,int type,...)611 _krb5_config_get_next (krb5_context context,
612 const krb5_config_section *c,
613 const krb5_config_binding **pointer,
614 int type,
615 ...)
616 {
617 const char *ret;
618 va_list args;
619
620 va_start(args, type);
621 ret = _krb5_config_vget_next (context, c, pointer, type, args);
622 va_end(args);
623 return ret;
624 }
625
626 static const void *
vget_next(krb5_context context,const krb5_config_binding * b,const krb5_config_binding ** pointer,int type,const char * name,va_list args)627 vget_next(krb5_context context,
628 const krb5_config_binding *b,
629 const krb5_config_binding **pointer,
630 int type,
631 const char *name,
632 va_list args)
633 {
634 const char *p = va_arg(args, const char *);
635 while(b != NULL) {
636 if(strcmp(b->name, name) == 0) {
637 if(b->type == (unsigned)type && p == NULL) {
638 *pointer = b;
639 return b->u.generic;
640 } else if(b->type == krb5_config_list && p != NULL) {
641 return vget_next(context, b->u.list, pointer, type, p, args);
642 }
643 }
644 b = b->next;
645 }
646 return NULL;
647 }
648
649 KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL
_krb5_config_vget_next(krb5_context context,const krb5_config_section * c,const krb5_config_binding ** pointer,int type,va_list args)650 _krb5_config_vget_next (krb5_context context,
651 const krb5_config_section *c,
652 const krb5_config_binding **pointer,
653 int type,
654 va_list args)
655 {
656 const krb5_config_binding *b;
657 const char *p;
658
659 if(c == NULL)
660 c = context->cf;
661
662 if (c == NULL)
663 return NULL;
664
665 if (*pointer == NULL) {
666 /* first time here, walk down the tree looking for the right
667 section */
668 p = va_arg(args, const char *);
669 if (p == NULL)
670 return NULL;
671 return vget_next(context, c, pointer, type, p, args);
672 }
673
674 /* we were called again, so just look for more entries with the
675 same name and type */
676 for (b = (*pointer)->next; b != NULL; b = b->next) {
677 if(strcmp(b->name, (*pointer)->name) == 0 && b->type == (unsigned)type) {
678 *pointer = b;
679 return b->u.generic;
680 }
681 }
682 return NULL;
683 }
684
685 KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL
_krb5_config_get(krb5_context context,const krb5_config_section * c,int type,...)686 _krb5_config_get (krb5_context context,
687 const krb5_config_section *c,
688 int type,
689 ...)
690 {
691 const void *ret;
692 va_list args;
693
694 va_start(args, type);
695 ret = _krb5_config_vget (context, c, type, args);
696 va_end(args);
697 return ret;
698 }
699
700
701 KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL
_krb5_config_vget(krb5_context context,const krb5_config_section * c,int type,va_list args)702 _krb5_config_vget (krb5_context context,
703 const krb5_config_section *c,
704 int type,
705 va_list args)
706 {
707 const krb5_config_binding *foo = NULL;
708
709 return _krb5_config_vget_next (context, c, &foo, type, args);
710 }
711
712 /**
713 * Get a list of configuration binding list for more processing
714 *
715 * @param context A Kerberos 5 context.
716 * @param c a configuration section, or NULL to use the section from context
717 * @param ... a list of names, terminated with NULL.
718 *
719 * @return NULL if configuration list is not found, a list otherwise
720 *
721 * @ingroup krb5_support
722 */
723
724 KRB5_LIB_FUNCTION const krb5_config_binding * KRB5_LIB_CALL
krb5_config_get_list(krb5_context context,const krb5_config_section * c,...)725 krb5_config_get_list (krb5_context context,
726 const krb5_config_section *c,
727 ...)
728 {
729 const krb5_config_binding *ret;
730 va_list args;
731
732 va_start(args, c);
733 ret = krb5_config_vget_list (context, c, args);
734 va_end(args);
735 return ret;
736 }
737
738 /**
739 * Get a list of configuration binding list for more processing
740 *
741 * @param context A Kerberos 5 context.
742 * @param c a configuration section, or NULL to use the section from context
743 * @param args a va_list of arguments
744 *
745 * @return NULL if configuration list is not found, a list otherwise
746 *
747 * @ingroup krb5_support
748 */
749
750 KRB5_LIB_FUNCTION const krb5_config_binding * KRB5_LIB_CALL
krb5_config_vget_list(krb5_context context,const krb5_config_section * c,va_list args)751 krb5_config_vget_list (krb5_context context,
752 const krb5_config_section *c,
753 va_list args)
754 {
755 return _krb5_config_vget (context, c, krb5_config_list, args);
756 }
757
758 /**
759 * Returns a "const char *" to a string in the configuration database.
760 * The string may not be valid after a reload of the configuration
761 * database so a caller should make a local copy if it needs to keep
762 * the string.
763 *
764 * @param context A Kerberos 5 context.
765 * @param c a configuration section, or NULL to use the section from context
766 * @param ... a list of names, terminated with NULL.
767 *
768 * @return NULL if configuration string not found, a string otherwise
769 *
770 * @ingroup krb5_support
771 */
772
773 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
krb5_config_get_string(krb5_context context,const krb5_config_section * c,...)774 krb5_config_get_string (krb5_context context,
775 const krb5_config_section *c,
776 ...)
777 {
778 const char *ret;
779 va_list args;
780
781 va_start(args, c);
782 ret = krb5_config_vget_string (context, c, args);
783 va_end(args);
784 return ret;
785 }
786
787 /**
788 * Like krb5_config_get_string(), but uses a va_list instead of ...
789 *
790 * @param context A Kerberos 5 context.
791 * @param c a configuration section, or NULL to use the section from context
792 * @param args a va_list of arguments
793 *
794 * @return NULL if configuration string not found, a string otherwise
795 *
796 * @ingroup krb5_support
797 */
798
799 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
krb5_config_vget_string(krb5_context context,const krb5_config_section * c,va_list args)800 krb5_config_vget_string (krb5_context context,
801 const krb5_config_section *c,
802 va_list args)
803 {
804 return _krb5_config_vget (context, c, krb5_config_string, args);
805 }
806
807 /**
808 * Like krb5_config_vget_string(), but instead of returning NULL,
809 * instead return a default value.
810 *
811 * @param context A Kerberos 5 context.
812 * @param c a configuration section, or NULL to use the section from context
813 * @param def_value the default value to return if no configuration
814 * found in the database.
815 * @param args a va_list of arguments
816 *
817 * @return a configuration string
818 *
819 * @ingroup krb5_support
820 */
821
822 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
krb5_config_vget_string_default(krb5_context context,const krb5_config_section * c,const char * def_value,va_list args)823 krb5_config_vget_string_default (krb5_context context,
824 const krb5_config_section *c,
825 const char *def_value,
826 va_list args)
827 {
828 const char *ret;
829
830 ret = krb5_config_vget_string (context, c, args);
831 if (ret == NULL)
832 ret = def_value;
833 return ret;
834 }
835
836 /**
837 * Like krb5_config_get_string(), but instead of returning NULL,
838 * instead return a default value.
839 *
840 * @param context A Kerberos 5 context.
841 * @param c a configuration section, or NULL to use the section from context
842 * @param def_value the default value to return if no configuration
843 * found in the database.
844 * @param ... a list of names, terminated with NULL.
845 *
846 * @return a configuration string
847 *
848 * @ingroup krb5_support
849 */
850
851 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
krb5_config_get_string_default(krb5_context context,const krb5_config_section * c,const char * def_value,...)852 krb5_config_get_string_default (krb5_context context,
853 const krb5_config_section *c,
854 const char *def_value,
855 ...)
856 {
857 const char *ret;
858 va_list args;
859
860 va_start(args, def_value);
861 ret = krb5_config_vget_string_default (context, c, def_value, args);
862 va_end(args);
863 return ret;
864 }
865
866 static char *
next_component_string(char * begin,const char * delims,char ** state)867 next_component_string(char * begin, const char * delims, char **state)
868 {
869 char * end;
870
871 if (begin == NULL)
872 begin = *state;
873
874 if (*begin == '\0')
875 return NULL;
876
877 end = begin;
878 while (*end == '"') {
879 char * t = strchr(end + 1, '"');
880
881 if (t)
882 end = ++t;
883 else
884 end += strlen(end);
885 }
886
887 if (*end != '\0') {
888 size_t pos;
889
890 pos = strcspn(end, delims);
891 end = end + pos;
892 }
893
894 if (*end != '\0') {
895 *end = '\0';
896 *state = end + 1;
897 if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) {
898 begin++; *(end - 1) = '\0';
899 }
900 return begin;
901 }
902
903 *state = end;
904 if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) {
905 begin++; *(end - 1) = '\0';
906 }
907 return begin;
908 }
909
910 /**
911 * Get a list of configuration strings, free the result with
912 * krb5_config_free_strings().
913 *
914 * @param context A Kerberos 5 context.
915 * @param c a configuration section, or NULL to use the section from context
916 * @param args a va_list of arguments
917 *
918 * @return TRUE or FALSE
919 *
920 * @ingroup krb5_support
921 */
922
923 KRB5_LIB_FUNCTION char ** KRB5_LIB_CALL
krb5_config_vget_strings(krb5_context context,const krb5_config_section * c,va_list args)924 krb5_config_vget_strings(krb5_context context,
925 const krb5_config_section *c,
926 va_list args)
927 {
928 char **strings = NULL;
929 int nstr = 0;
930 const krb5_config_binding *b = NULL;
931 const char *p;
932
933 while((p = _krb5_config_vget_next(context, c, &b,
934 krb5_config_string, args))) {
935 char *tmp = strdup(p);
936 char *pos = NULL;
937 char *s;
938 if(tmp == NULL)
939 goto cleanup;
940 s = next_component_string(tmp, " \t", &pos);
941 while(s){
942 char **tmp2 = realloc(strings, (nstr + 1) * sizeof(*strings));
943 if(tmp2 == NULL) {
944 free(tmp);
945 goto cleanup;
946 }
947 strings = tmp2;
948 strings[nstr] = strdup(s);
949 nstr++;
950 if(strings[nstr-1] == NULL) {
951 free(tmp);
952 goto cleanup;
953 }
954 s = next_component_string(NULL, " \t", &pos);
955 }
956 free(tmp);
957 }
958 if(nstr){
959 char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings));
960 if(tmp == NULL)
961 goto cleanup;
962 strings = tmp;
963 strings[nstr] = NULL;
964 }
965 return strings;
966 cleanup:
967 while(nstr--)
968 free(strings[nstr]);
969 free(strings);
970 return NULL;
971
972 }
973
974 /**
975 * Get a list of configuration strings, free the result with
976 * krb5_config_free_strings().
977 *
978 * @param context A Kerberos 5 context.
979 * @param c a configuration section, or NULL to use the section from context
980 * @param ... a list of names, terminated with NULL.
981 *
982 * @return TRUE or FALSE
983 *
984 * @ingroup krb5_support
985 */
986
987 KRB5_LIB_FUNCTION char** KRB5_LIB_CALL
krb5_config_get_strings(krb5_context context,const krb5_config_section * c,...)988 krb5_config_get_strings(krb5_context context,
989 const krb5_config_section *c,
990 ...)
991 {
992 va_list ap;
993 char **ret;
994 va_start(ap, c);
995 ret = krb5_config_vget_strings(context, c, ap);
996 va_end(ap);
997 return ret;
998 }
999
1000 /**
1001 * Free the resulting strings from krb5_config-get_strings() and
1002 * krb5_config_vget_strings().
1003 *
1004 * @param strings strings to free
1005 *
1006 * @ingroup krb5_support
1007 */
1008
1009 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_config_free_strings(char ** strings)1010 krb5_config_free_strings(char **strings)
1011 {
1012 char **s = strings;
1013 while(s && *s){
1014 free(*s);
1015 s++;
1016 }
1017 free(strings);
1018 }
1019
1020 /**
1021 * Like krb5_config_get_bool_default() but with a va_list list of
1022 * configuration selection.
1023 *
1024 * Configuration value to a boolean value, where yes/true and any
1025 * non-zero number means TRUE and other value is FALSE.
1026 *
1027 * @param context A Kerberos 5 context.
1028 * @param c a configuration section, or NULL to use the section from context
1029 * @param def_value the default value to return if no configuration
1030 * found in the database.
1031 * @param args a va_list of arguments
1032 *
1033 * @return TRUE or FALSE
1034 *
1035 * @ingroup krb5_support
1036 */
1037
1038 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_config_vget_bool_default(krb5_context context,const krb5_config_section * c,krb5_boolean def_value,va_list args)1039 krb5_config_vget_bool_default (krb5_context context,
1040 const krb5_config_section *c,
1041 krb5_boolean def_value,
1042 va_list args)
1043 {
1044 const char *str;
1045 str = krb5_config_vget_string (context, c, args);
1046 if(str == NULL)
1047 return def_value;
1048 if(strcasecmp(str, "yes") == 0 ||
1049 strcasecmp(str, "true") == 0 ||
1050 atoi(str)) return TRUE;
1051 return FALSE;
1052 }
1053
1054 /**
1055 * krb5_config_get_bool() will convert the configuration
1056 * option value to a boolean value, where yes/true and any non-zero
1057 * number means TRUE and other value is FALSE.
1058 *
1059 * @param context A Kerberos 5 context.
1060 * @param c a configuration section, or NULL to use the section from context
1061 * @param args a va_list of arguments
1062 *
1063 * @return TRUE or FALSE
1064 *
1065 * @ingroup krb5_support
1066 */
1067
1068 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_config_vget_bool(krb5_context context,const krb5_config_section * c,va_list args)1069 krb5_config_vget_bool (krb5_context context,
1070 const krb5_config_section *c,
1071 va_list args)
1072 {
1073 return krb5_config_vget_bool_default (context, c, FALSE, args);
1074 }
1075
1076 /**
1077 * krb5_config_get_bool_default() will convert the configuration
1078 * option value to a boolean value, where yes/true and any non-zero
1079 * number means TRUE and other value is FALSE.
1080 *
1081 * @param context A Kerberos 5 context.
1082 * @param c a configuration section, or NULL to use the section from context
1083 * @param def_value the default value to return if no configuration
1084 * found in the database.
1085 * @param ... a list of names, terminated with NULL.
1086 *
1087 * @return TRUE or FALSE
1088 *
1089 * @ingroup krb5_support
1090 */
1091
1092 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_config_get_bool_default(krb5_context context,const krb5_config_section * c,krb5_boolean def_value,...)1093 krb5_config_get_bool_default (krb5_context context,
1094 const krb5_config_section *c,
1095 krb5_boolean def_value,
1096 ...)
1097 {
1098 va_list ap;
1099 krb5_boolean ret;
1100 va_start(ap, def_value);
1101 ret = krb5_config_vget_bool_default(context, c, def_value, ap);
1102 va_end(ap);
1103 return ret;
1104 }
1105
1106 /**
1107 * Like krb5_config_get_bool() but with a va_list list of
1108 * configuration selection.
1109 *
1110 * Configuration value to a boolean value, where yes/true and any
1111 * non-zero number means TRUE and other value is FALSE.
1112 *
1113 * @param context A Kerberos 5 context.
1114 * @param c a configuration section, or NULL to use the section from context
1115 * @param ... a list of names, terminated with NULL.
1116 *
1117 * @return TRUE or FALSE
1118 *
1119 * @ingroup krb5_support
1120 */
1121
1122 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_config_get_bool(krb5_context context,const krb5_config_section * c,...)1123 krb5_config_get_bool (krb5_context context,
1124 const krb5_config_section *c,
1125 ...)
1126 {
1127 va_list ap;
1128 krb5_boolean ret;
1129 va_start(ap, c);
1130 ret = krb5_config_vget_bool (context, c, ap);
1131 va_end(ap);
1132 return ret;
1133 }
1134
1135 /**
1136 * Get the time from the configuration file using a relative time.
1137 *
1138 * Like krb5_config_get_time_default() but with a va_list list of
1139 * configuration selection.
1140 *
1141 * @param context A Kerberos 5 context.
1142 * @param c a configuration section, or NULL to use the section from context
1143 * @param def_value the default value to return if no configuration
1144 * found in the database.
1145 * @param args a va_list of arguments
1146 *
1147 * @return parsed the time (or def_value on parse error)
1148 *
1149 * @ingroup krb5_support
1150 */
1151
1152 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
krb5_config_vget_time_default(krb5_context context,const krb5_config_section * c,int def_value,va_list args)1153 krb5_config_vget_time_default (krb5_context context,
1154 const krb5_config_section *c,
1155 int def_value,
1156 va_list args)
1157 {
1158 const char *str;
1159 krb5_deltat t;
1160
1161 str = krb5_config_vget_string (context, c, args);
1162 if(str == NULL)
1163 return def_value;
1164 if (krb5_string_to_deltat(str, &t))
1165 return def_value;
1166 return t;
1167 }
1168
1169 /**
1170 * Get the time from the configuration file using a relative time, for example: 1h30s
1171 *
1172 * @param context A Kerberos 5 context.
1173 * @param c a configuration section, or NULL to use the section from context
1174 * @param args a va_list of arguments
1175 *
1176 * @return parsed the time or -1 on error
1177 *
1178 * @ingroup krb5_support
1179 */
1180
1181 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
krb5_config_vget_time(krb5_context context,const krb5_config_section * c,va_list args)1182 krb5_config_vget_time (krb5_context context,
1183 const krb5_config_section *c,
1184 va_list args)
1185 {
1186 return krb5_config_vget_time_default (context, c, -1, args);
1187 }
1188
1189 /**
1190 * Get the time from the configuration file using a relative time, for example: 1h30s
1191 *
1192 * @param context A Kerberos 5 context.
1193 * @param c a configuration section, or NULL to use the section from context
1194 * @param def_value the default value to return if no configuration
1195 * found in the database.
1196 * @param ... a list of names, terminated with NULL.
1197 *
1198 * @return parsed the time (or def_value on parse error)
1199 *
1200 * @ingroup krb5_support
1201 */
1202
1203 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
krb5_config_get_time_default(krb5_context context,const krb5_config_section * c,int def_value,...)1204 krb5_config_get_time_default (krb5_context context,
1205 const krb5_config_section *c,
1206 int def_value,
1207 ...)
1208 {
1209 va_list ap;
1210 int ret;
1211 va_start(ap, def_value);
1212 ret = krb5_config_vget_time_default(context, c, def_value, ap);
1213 va_end(ap);
1214 return ret;
1215 }
1216
1217 /**
1218 * Get the time from the configuration file using a relative time, for example: 1h30s
1219 *
1220 * @param context A Kerberos 5 context.
1221 * @param c a configuration section, or NULL to use the section from context
1222 * @param ... a list of names, terminated with NULL.
1223 *
1224 * @return parsed the time or -1 on error
1225 *
1226 * @ingroup krb5_support
1227 */
1228
1229 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
krb5_config_get_time(krb5_context context,const krb5_config_section * c,...)1230 krb5_config_get_time (krb5_context context,
1231 const krb5_config_section *c,
1232 ...)
1233 {
1234 va_list ap;
1235 int ret;
1236 va_start(ap, c);
1237 ret = krb5_config_vget_time (context, c, ap);
1238 va_end(ap);
1239 return ret;
1240 }
1241
1242
1243 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
krb5_config_vget_int_default(krb5_context context,const krb5_config_section * c,int def_value,va_list args)1244 krb5_config_vget_int_default (krb5_context context,
1245 const krb5_config_section *c,
1246 int def_value,
1247 va_list args)
1248 {
1249 const char *str;
1250 str = krb5_config_vget_string (context, c, args);
1251 if(str == NULL)
1252 return def_value;
1253 else {
1254 char *endptr;
1255 long l;
1256 l = strtol(str, &endptr, 0);
1257 if (endptr == str)
1258 return def_value;
1259 else
1260 return l;
1261 }
1262 }
1263
1264 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
krb5_config_vget_int(krb5_context context,const krb5_config_section * c,va_list args)1265 krb5_config_vget_int (krb5_context context,
1266 const krb5_config_section *c,
1267 va_list args)
1268 {
1269 return krb5_config_vget_int_default (context, c, -1, args);
1270 }
1271
1272 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
krb5_config_get_int_default(krb5_context context,const krb5_config_section * c,int def_value,...)1273 krb5_config_get_int_default (krb5_context context,
1274 const krb5_config_section *c,
1275 int def_value,
1276 ...)
1277 {
1278 va_list ap;
1279 int ret;
1280 va_start(ap, def_value);
1281 ret = krb5_config_vget_int_default(context, c, def_value, ap);
1282 va_end(ap);
1283 return ret;
1284 }
1285
1286 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
krb5_config_get_int(krb5_context context,const krb5_config_section * c,...)1287 krb5_config_get_int (krb5_context context,
1288 const krb5_config_section *c,
1289 ...)
1290 {
1291 va_list ap;
1292 int ret;
1293 va_start(ap, c);
1294 ret = krb5_config_vget_int (context, c, ap);
1295 va_end(ap);
1296 return ret;
1297 }
1298
1299
1300 #ifndef HEIMDAL_SMALLER
1301
1302 /**
1303 * Deprecated: configuration files are not strings
1304 *
1305 * @ingroup krb5_deprecated
1306 */
1307
1308 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_config_parse_string_multi(krb5_context context,const char * string,krb5_config_section ** res)1309 krb5_config_parse_string_multi(krb5_context context,
1310 const char *string,
1311 krb5_config_section **res)
1312 KRB5_DEPRECATED_FUNCTION("Use X instead")
1313 {
1314 const char *str;
1315 unsigned lineno = 0;
1316 krb5_error_code ret;
1317 struct fileptr f;
1318 f.f = NULL;
1319 f.s = string;
1320
1321 ret = krb5_config_parse_debug (&f, res, &lineno, &str);
1322 if (ret) {
1323 krb5_set_error_message (context, ret, "%s:%u: %s",
1324 "<constant>", lineno, str);
1325 return ret;
1326 }
1327 return 0;
1328 }
1329
1330 #endif
1331