gp: Test with binary content for certificate data
[Samba.git] / third_party / heimdal / lib / base / config_file.c
blobb1675ea5f141e1db5399dc6b6683c37cd004ebc6
1 /*
2 * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include "baselocl.h"
37 #include <assert.h>
38 #include <ctype.h>
39 #include <parse_time.h>
41 #if defined(HAVE_FRAMEWORK_COREFOUNDATION)
42 #include <CoreFoundation/CoreFoundation.h>
43 #endif
45 /* Gaah! I want a portable funopen */
46 struct fileptr {
47 heim_context context;
48 const char *s;
49 FILE *f;
52 static char *
53 config_fgets(char *str, size_t len, struct fileptr *ptr)
55 /* XXX this is not correct, in that they don't do the same if the
56 line is longer than len */
57 if(ptr->f != NULL)
58 return fgets(str, len, ptr->f);
59 else {
60 /* this is almost strsep_copy */
61 const char *p;
62 ssize_t l;
63 if(*ptr->s == '\0')
64 return NULL;
65 p = ptr->s + strcspn(ptr->s, "\n");
66 if(*p == '\n')
67 p++;
68 l = min(len, (size_t)(p - ptr->s));
69 if(len > 0) {
70 memcpy(str, ptr->s, l);
71 str[l] = '\0';
73 ptr->s = p;
74 return str;
78 static heim_error_code parse_section(char *p, heim_config_section **s,
79 heim_config_section **res,
80 const char **err_message);
81 static heim_error_code parse_binding(struct fileptr *f, unsigned *lineno, char *p,
82 heim_config_binding **b,
83 heim_config_binding **parent,
84 const char **err_message);
85 static heim_error_code parse_list(struct fileptr *f, unsigned *lineno,
86 heim_config_binding **parent,
87 const char **err_message);
89 heim_config_section *
90 heim_config_get_entry(heim_config_section **parent, const char *name, int type)
92 heim_config_section **q;
94 for (q = parent; *q != NULL; q = &(*q)->next)
95 if (type == heim_config_list &&
96 (unsigned)type == (*q)->type &&
97 strcmp(name, (*q)->name) == 0)
98 return *q;
99 *q = calloc(1, sizeof(**q));
100 if (*q == NULL)
101 return NULL;
102 (*q)->name = strdup(name);
103 (*q)->type = type;
104 if ((*q)->name == NULL) {
105 free(*q);
106 *q = NULL;
107 return NULL;
109 return *q;
113 * Parse a section:
115 * [section]
116 * foo = bar
117 * b = {
120 * ...
122 * starting at the line in `p', storing the resulting structure in
123 * `s' and hooking it into `parent'.
124 * Store the error message in `err_message'.
127 static heim_error_code
128 parse_section(char *p, heim_config_section **s, heim_config_section **parent,
129 const char **err_message)
131 char *p1;
132 heim_config_section *tmp;
134 p1 = strchr (p + 1, ']');
135 if (p1 == NULL) {
136 *err_message = "missing ]";
137 return HEIM_ERR_CONFIG_BADFORMAT;
139 *p1 = '\0';
140 tmp = heim_config_get_entry(parent, p + 1, heim_config_list);
141 if(tmp == NULL) {
142 *err_message = "out of memory";
143 return HEIM_ERR_CONFIG_BADFORMAT;
145 *s = tmp;
146 return 0;
150 * Parse a brace-enclosed list from `f', hooking in the structure at
151 * `parent'.
152 * Store the error message in `err_message'.
155 static heim_error_code
156 parse_list(struct fileptr *f, unsigned *lineno, heim_config_binding **parent,
157 const char **err_message)
159 char buf[2048];
160 heim_error_code ret;
161 heim_config_binding *b = NULL;
162 unsigned beg_lineno = *lineno;
164 while(config_fgets(buf, sizeof(buf), f) != NULL) {
165 char *p;
167 ++*lineno;
168 buf[strcspn(buf, "\r\n")] = '\0';
169 p = buf;
170 while(isspace((unsigned char)*p))
171 ++p;
172 if (*p == '#' || *p == ';' || *p == '\0')
173 continue;
174 while(isspace((unsigned char)*p))
175 ++p;
176 if (*p == '}')
177 return 0;
178 if (*p == '\0')
179 continue;
180 ret = parse_binding (f, lineno, p, &b, parent, err_message);
181 if (ret)
182 return ret;
184 *lineno = beg_lineno;
185 *err_message = "unclosed {";
186 return HEIM_ERR_CONFIG_BADFORMAT;
193 static heim_error_code
194 parse_binding(struct fileptr *f, unsigned *lineno, char *p,
195 heim_config_binding **b, heim_config_binding **parent,
196 const char **err_message)
198 heim_config_binding *tmp;
199 char *p1, *p2;
200 heim_error_code ret = 0;
202 p1 = p;
203 while (*p && *p != '=' && !isspace((unsigned char)*p))
204 ++p;
205 if (*p == '\0') {
206 *err_message = "missing =";
207 return HEIM_ERR_CONFIG_BADFORMAT;
209 p2 = p;
210 while (isspace((unsigned char)*p))
211 ++p;
212 if (*p != '=') {
213 *err_message = "missing =";
214 return HEIM_ERR_CONFIG_BADFORMAT;
216 ++p;
217 while(isspace((unsigned char)*p))
218 ++p;
219 *p2 = '\0';
220 if (*p == '{') {
221 tmp = heim_config_get_entry(parent, p1, heim_config_list);
222 if (tmp == NULL) {
223 *err_message = "out of memory";
224 return HEIM_ERR_CONFIG_BADFORMAT;
226 ret = parse_list (f, lineno, &tmp->u.list, err_message);
227 } else {
228 tmp = heim_config_get_entry(parent, p1, heim_config_string);
229 if (tmp == NULL) {
230 *err_message = "out of memory";
231 return HEIM_ERR_CONFIG_BADFORMAT;
233 p1 = p;
234 p = p1 + strlen(p1);
235 while(p > p1 && isspace((unsigned char)*(p-1)))
236 --p;
237 *p = '\0';
238 tmp->u.string = strdup(p1);
240 *b = tmp;
241 return ret;
244 #if defined(HAVE_FRAMEWORK_COREFOUNDATION)
246 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
247 #define HAVE_CFPROPERTYLISTCREATEWITHSTREAM 1
248 #endif
250 static char *
251 cfstring2cstring(CFStringRef string)
253 CFIndex len;
254 char *str;
256 str = (char *) CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
257 if (str)
258 return strdup(str);
260 len = CFStringGetLength(string);
261 len = 1 + CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8);
262 str = malloc(len);
263 if (str == NULL)
264 return NULL;
266 if (!CFStringGetCString (string, str, len, kCFStringEncodingUTF8)) {
267 free (str);
268 return NULL;
270 return str;
273 static void
274 convert_content(const void *key, const void *value, void *context)
276 heim_config_section *tmp, **parent = context;
277 char *k;
279 if (CFGetTypeID(key) != CFStringGetTypeID())
280 return;
282 k = cfstring2cstring(key);
283 if (k == NULL)
284 return;
286 if (CFGetTypeID(value) == CFStringGetTypeID()) {
287 tmp = heim_config_get_entry(parent, k, heim_config_string);
288 tmp->u.string = cfstring2cstring(value);
289 } else if (CFGetTypeID(value) == CFDictionaryGetTypeID()) {
290 tmp = heim_config_get_entry(parent, k, heim_config_list);
291 CFDictionaryApplyFunction(value, convert_content, &tmp->u.list);
292 } else {
293 /* log */
295 free(k);
298 static heim_error_code
299 parse_plist_config(heim_context context, const char *path, heim_config_section **parent)
301 CFReadStreamRef s;
302 CFDictionaryRef d;
303 CFURLRef url;
305 url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)path, strlen(path), 0);
306 if (url == NULL) {
307 heim_clear_error_message(context);
308 return ENOMEM;
311 s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
312 CFRelease(url);
313 if (s == NULL) {
314 heim_clear_error_message(context);
315 return ENOMEM;
318 if (!CFReadStreamOpen(s)) {
319 CFRelease(s);
320 heim_clear_error_message(context);
321 return ENOENT;
324 #ifdef HAVE_CFPROPERTYLISTCREATEWITHSTREAM
325 d = (CFDictionaryRef)CFPropertyListCreateWithStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL);
326 #else
327 d = (CFDictionaryRef)CFPropertyListCreateFromStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL);
328 #endif
329 CFRelease(s);
330 if (d == NULL) {
331 heim_clear_error_message(context);
332 return ENOENT;
335 CFDictionaryApplyFunction(d, convert_content, parent);
336 CFRelease(d);
338 return 0;
341 #endif
343 static int
344 is_absolute_path(const char *path)
347 * An absolute path is one that refers to an explicit object
348 * without ambiguity.
350 #ifdef WIN32
351 size_t len = strlen(path);
353 /* UNC path is by definition absolute */
354 if (len > 2
355 && ISPATHSEP(path[0])
356 && ISPATHSEP(path[1]))
357 return 1;
359 /* A drive letter path might be absolute */
360 if (len > 3
361 && isalpha((unsigned char)path[0])
362 && path[1] == ':'
363 && ISPATHSEP(path[2]))
364 return 1;
367 * if no drive letter but first char is a path
368 * separator then the drive letter must be obtained
369 * from the including file.
371 #else
372 /* UNIX is easy, first char '/' is absolute */
373 if (ISPATHSEP(path[0]))
374 return 1;
375 #endif
376 return 0;
380 * Parse the config file `fname', generating the structures into `res'
381 * returning error messages in `err_message'
384 static heim_error_code
385 heim_config_parse_debug(struct fileptr *f,
386 heim_config_section **res,
387 unsigned *lineno,
388 const char **err_message)
390 heim_config_section *s = NULL;
391 heim_config_binding *b = NULL;
392 char buf[2048];
393 heim_error_code ret;
395 *lineno = 0;
396 *err_message = "";
398 while (config_fgets(buf, sizeof(buf), f) != NULL) {
399 char *p;
401 ++*lineno;
402 buf[strcspn(buf, "\r\n")] = '\0';
403 p = buf;
404 while(isspace((unsigned char)*p))
405 ++p;
406 if (*p == '#' || *p == ';')
407 continue;
408 if (*p == '[') {
409 ret = parse_section(p, &s, res, err_message);
410 if (ret)
411 return ret;
412 b = NULL;
413 } else if (*p == '}') {
414 *err_message = "unmatched }";
415 return 2048;
416 } else if (strncmp(p, "include", sizeof("include") - 1) == 0 &&
417 isspace((unsigned char)p[sizeof("include") - 1])) {
418 p += sizeof("include");
419 while (isspace((unsigned char)*p))
420 p++;
421 if (!is_absolute_path(p)) {
422 heim_set_error_message(f->context, HEIM_ERR_CONFIG_BADFORMAT,
423 "Configuration include path must be "
424 "absolute");
425 return HEIM_ERR_CONFIG_BADFORMAT;
427 ret = heim_config_parse_file_multi(f->context, p, res);
428 if (ret)
429 return ret;
430 } else if (strncmp(p, "includedir", sizeof("includedir") - 1) == 0 &&
431 isspace((unsigned char)p[sizeof("includedir") - 1])) {
432 p += sizeof("includedir");
433 while (isspace((unsigned char)*p))
434 p++;
435 if (!is_absolute_path(p)) {
436 heim_set_error_message(f->context, HEIM_ERR_CONFIG_BADFORMAT,
437 "Configuration includedir path must be "
438 "absolute");
439 return HEIM_ERR_CONFIG_BADFORMAT;
441 ret = heim_config_parse_dir_multi(f->context, p, res);
442 if (ret)
443 return ret;
444 } else if(*p != '\0') {
445 if (s == NULL) {
446 *err_message = "binding before section";
447 return 2048;
449 ret = parse_binding(f, lineno, p, &b, &s->u.list, err_message);
450 if (ret)
451 return ret;
454 return 0;
457 static int
458 is_plist_file(const char *fname)
460 size_t len = strlen(fname);
461 char suffix[] = ".plist";
462 if (len < sizeof(suffix))
463 return 0;
464 if (strcasecmp(&fname[len - (sizeof(suffix) - 1)], suffix) != 0)
465 return 0;
466 return 1;
470 * Parse configuration files in the given directory and add the result
471 * into res. Only files whose names consist only of alphanumeric
472 * characters, hyphen, and underscore, will be parsed, though files
473 * ending in ".conf" will also be parsed.
475 * This interface can be used to parse several configuration directories
476 * into one resulting heim_config_section by calling it repeatably.
478 * @param context a Kerberos 5 context.
479 * @param dname a directory name to a Kerberos configuration file
480 * @param res the returned result, must be free with heim_free_config_files().
481 * @return Return an error code or 0, see heim_get_error_message().
483 * @ingroup heim_support
486 heim_error_code
487 heim_config_parse_dir_multi(heim_context context,
488 const char *dname,
489 heim_config_section **res)
491 struct dirent *entry;
492 heim_error_code ret;
493 DIR *d;
495 if ((d = opendir(dname)) == NULL)
496 return errno;
498 while ((entry = readdir(d)) != NULL) {
499 char *p = entry->d_name;
500 char *path;
501 int is_valid = 1;
503 while (*p) {
505 * Here be dragons. The call to heim_config_parse_file_multi()
506 * below expands path tokens. Because of the limitations here
507 * on file naming, we can't have path tokens in the file name,
508 * so we're safe. Anyone changing this if condition here should
509 * be aware.
511 if (!isalnum((unsigned char)*p) && *p != '_' && *p != '-' &&
512 strcmp(p, ".conf") != 0) {
513 is_valid = 0;
514 break;
516 p++;
518 if (!is_valid)
519 continue;
521 if (asprintf(&path, "%s/%s", dname, entry->d_name) == -1 ||
522 path == NULL) {
523 (void) closedir(d);
524 return heim_enomem(context);
526 ret = heim_config_parse_file_multi(context, path, res);
527 free(path);
528 if (ret == ENOMEM) {
529 (void) closedir(d);
530 return ENOMEM;
532 /* Ignore malformed config files so we don't lock out admins, etc... */
534 (void) closedir(d);
535 return 0;
538 static int
539 is_devnull(struct stat *st)
541 #ifdef WIN32
542 return 0;
543 #else
544 struct stat devnullst;
546 if (stat("/dev/null", &devnullst) == -1)
547 return 0;
548 return st->st_dev == devnullst.st_dev && st->st_ino == devnullst.st_ino;
549 #endif
552 HEIMDAL_THREAD_LOCAL int config_include_depth = 0;
555 * Parse a configuration file and add the result into res. This
556 * interface can be used to parse several configuration files into one
557 * resulting heim_config_section by calling it repeatably.
559 * @param context a Kerberos 5 context.
560 * @param fname a file name to a Kerberos configuration file
561 * @param res the returned result, must be free with heim_free_config_files().
562 * @return Return an error code or 0, see heim_get_error_message().
564 * @ingroup heim_support
567 heim_error_code
568 heim_config_parse_file_multi(heim_context context,
569 const char *fname,
570 heim_config_section **res)
572 const char *str;
573 char *newfname = NULL;
574 unsigned lineno = 0;
575 heim_error_code ret = 0;
576 struct fileptr f;
577 struct stat st;
579 if (config_include_depth > 5) {
580 heim_warnx(context, "Maximum config file include depth reached; "
581 "not including %s", fname);
582 return 0;
584 config_include_depth++;
587 * If the fname starts with "~/" parse configuration file in the
588 * current users home directory. The behavior can be disabled and
589 * enabled by calling heim_set_home_dir_access().
591 if (ISTILDE(fname[0]) && ISPATHSEP(fname[1])) {
592 if (!heim_context_get_homedir_access(context)) {
593 heim_set_error_message(context, EPERM,
594 "Access to home directory not allowed");
595 ret = EPERM;
596 goto out;
598 if (asprintf(&newfname, "%%{USERCONFIG}%s", &fname[1]) < 0 ||
599 newfname == NULL) {
600 ret = heim_enomem(context);
601 goto out;
603 fname = newfname;
606 if (is_plist_file(fname)) {
607 #if defined(HAVE_FRAMEWORK_COREFOUNDATION)
608 ret = parse_plist_config(context, fname, res);
609 if (ret) {
610 heim_set_error_message(context, ret,
611 "Failed to parse plist %s", fname);
612 goto out;
614 #else
615 heim_set_error_message(context, ENOENT,
616 "no support for plist configuration files");
617 ret = ENOENT;
618 goto out;
619 #endif
620 } else {
621 char *exp_fname = NULL;
624 * Note that heim_config_parse_dir_multi() doesn't want tokens
625 * expanded here, but it happens to limit the names of files to
626 * include such that there can be no tokens to expand. Don't
627 * add token expansion for tokens using _, say.
629 ret = heim_expand_path_tokens(context, fname, 1, &exp_fname, NULL);
630 if (ret)
631 goto out;
632 free(newfname);
633 fname = newfname = exp_fname;
635 f.context = context;
636 f.f = fopen(fname, "r");
637 f.s = NULL;
638 if (f.f == NULL || fstat(fileno(f.f), &st) == -1) {
639 if (f.f != NULL)
640 (void) fclose(f.f);
641 ret = errno;
642 heim_set_error_message(context, ret, "open or stat %s: %s",
643 fname, strerror(ret));
644 goto out;
647 if (!S_ISREG(st.st_mode) && !is_devnull(&st)) {
648 (void) fclose(f.f);
649 heim_set_error_message(context, EISDIR, "not a regular file %s: %s",
650 fname, strerror(EISDIR));
651 ret = EISDIR;
652 goto out;
655 ret = heim_config_parse_debug(&f, res, &lineno, &str);
656 fclose(f.f);
657 if (ret) {
658 if (ret != HEIM_ERR_CONFIG_BADFORMAT)
659 ret = HEIM_ERR_CONFIG_BADFORMAT;
660 heim_set_error_message(context, ret, "%s:%u: %s",
661 fname, lineno, str);
662 goto out;
666 out:
667 config_include_depth--;
668 if (ret == HEIM_ERR_CONFIG_BADFORMAT || (ret && config_include_depth > 0)) {
669 heim_warn(context, ret, "Ignoring");
670 if (config_include_depth > 0)
671 ret = 0;
673 free(newfname);
674 return ret;
677 heim_error_code
678 heim_config_parse_file(heim_context context,
679 const char *fname,
680 heim_config_section **res)
682 *res = NULL;
683 return heim_config_parse_file_multi(context, fname, res);
686 static void
687 free_binding(heim_context context, heim_config_binding *b)
689 heim_config_binding *next_b;
691 while (b) {
692 free (b->name);
693 assert(b->type == heim_config_string || b->type == heim_config_list);
694 if (b->type == heim_config_string)
695 free (b->u.string);
696 else
697 free_binding (context, b->u.list);
698 next_b = b->next;
699 free (b);
700 b = next_b;
705 * Free configuration file section, the result of
706 * heim_config_parse_file() and heim_config_parse_file_multi().
708 * @param context A Kerberos 5 context
709 * @param s the configuration section to free
711 * @return returns 0 on successes, otherwise an error code, see
712 * heim_get_error_message()
714 * @ingroup heim_support
717 heim_error_code
718 heim_config_file_free(heim_context context, heim_config_section *s)
720 free_binding (context, s);
721 return 0;
724 #ifndef HEIMDAL_SMALLER
726 heim_error_code
727 heim_config_copy(heim_context context,
728 heim_config_section *c,
729 heim_config_section **head)
731 heim_config_binding *d, *previous = NULL;
733 *head = NULL;
735 while (c) {
736 d = calloc(1, sizeof(*d));
738 if (*head == NULL)
739 *head = d;
741 d->name = strdup(c->name);
742 d->type = c->type;
743 assert(d->type == heim_config_string || d->type == heim_config_list);
744 if (d->type == heim_config_string)
745 d->u.string = strdup(c->u.string);
746 else
747 heim_config_copy (context, c->u.list, &d->u.list);
748 if (previous)
749 previous->next = d;
751 previous = d;
752 c = c->next;
754 return 0;
757 #endif /* HEIMDAL_SMALLER */
759 const void *
760 heim_config_get_next(heim_context context,
761 const heim_config_section *c,
762 const heim_config_binding **pointer,
763 int type,
764 ...)
766 const char *ret;
767 va_list args;
769 va_start(args, type);
770 ret = heim_config_vget_next(context, c, pointer, type, args);
771 va_end(args);
772 return ret;
775 static const void *
776 vget_next(heim_context context,
777 const heim_config_binding *b,
778 const heim_config_binding **pointer,
779 int type,
780 const char *name,
781 va_list args)
783 const char *p = va_arg(args, const char *);
785 while (b != NULL) {
786 if (strcmp(b->name, name) == 0) {
787 if (b->type == (unsigned)type && p == NULL) {
788 *pointer = b;
789 return b->u.generic;
790 } else if (b->type == heim_config_list && p != NULL) {
791 return vget_next(context, b->u.list, pointer, type, p, args);
794 b = b->next;
796 return NULL;
799 const void *
800 heim_config_vget_next(heim_context context,
801 const heim_config_section *c,
802 const heim_config_binding **pointer,
803 int type,
804 va_list args)
806 const heim_config_binding *b;
807 const char *p;
809 if (c == NULL)
810 return NULL;
812 if (*pointer == NULL) {
813 /* first time here, walk down the tree looking for the right
814 section */
815 p = va_arg(args, const char *);
816 if (p == NULL)
817 return NULL;
818 return vget_next(context, c, pointer, type, p, args);
821 /* we were called again, so just look for more entries with the
822 same name and type */
823 for (b = (*pointer)->next; b != NULL; b = b->next) {
824 if(strcmp(b->name, (*pointer)->name) == 0 && b->type == (unsigned)type) {
825 *pointer = b;
826 return b->u.generic;
829 return NULL;
832 const void *
833 heim_config_get(heim_context context,
834 const heim_config_section *c,
835 int type,
836 ...)
838 const void *ret;
839 va_list args;
841 va_start(args, type);
842 ret = heim_config_vget(context, c, type, args);
843 va_end(args);
844 return ret;
848 const void *
849 heim_config_vget(heim_context context,
850 const heim_config_section *c,
851 int type,
852 va_list args)
854 const heim_config_binding *foo = NULL;
856 return heim_config_vget_next(context, c, &foo, type, args);
860 * Get a list of configuration binding list for more processing
862 * @param context A Kerberos 5 context.
863 * @param c a configuration section, or NULL to use the section from context
864 * @param ... a list of names, terminated with NULL.
866 * @return NULL if configuration list is not found, a list otherwise
868 * @ingroup heim_support
871 const heim_config_binding *
872 heim_config_get_list(heim_context context,
873 const heim_config_section *c,
874 ...)
876 const heim_config_binding *ret;
877 va_list args;
879 va_start(args, c);
880 ret = heim_config_vget_list(context, c, args);
881 va_end(args);
882 return ret;
886 * Get a list of configuration binding list for more processing
888 * @param context A Kerberos 5 context.
889 * @param c a configuration section, or NULL to use the section from context
890 * @param args a va_list of arguments
892 * @return NULL if configuration list is not found, a list otherwise
894 * @ingroup heim_support
897 const heim_config_binding *
898 heim_config_vget_list(heim_context context,
899 const heim_config_section *c,
900 va_list args)
902 return heim_config_vget(context, c, heim_config_list, args);
906 * Returns a "const char *" to a string in the configuration database.
907 * The string may not be valid after a reload of the configuration
908 * database so a caller should make a local copy if it needs to keep
909 * the string.
911 * @param context A Kerberos 5 context.
912 * @param c a configuration section, or NULL to use the section from context
913 * @param ... a list of names, terminated with NULL.
915 * @return NULL if configuration string not found, a string otherwise
917 * @ingroup heim_support
920 const char *
921 heim_config_get_string(heim_context context,
922 const heim_config_section *c,
923 ...)
925 const char *ret;
926 va_list args;
928 va_start(args, c);
929 ret = heim_config_vget_string(context, c, args);
930 va_end(args);
931 return ret;
935 * Like heim_config_get_string(), but uses a va_list instead of ...
937 * @param context A Kerberos 5 context.
938 * @param c a configuration section, or NULL to use the section from context
939 * @param args a va_list of arguments
941 * @return NULL if configuration string not found, a string otherwise
943 * @ingroup heim_support
946 const char *
947 heim_config_vget_string(heim_context context,
948 const heim_config_section *c,
949 va_list args)
951 return heim_config_vget(context, c, heim_config_string, args);
955 * Like heim_config_vget_string(), but instead of returning NULL,
956 * instead return a default value.
958 * @param context A Kerberos 5 context.
959 * @param c a configuration section, or NULL to use the section from context
960 * @param def_value the default value to return if no configuration
961 * found in the database.
962 * @param args a va_list of arguments
964 * @return a configuration string
966 * @ingroup heim_support
969 const char *
970 heim_config_vget_string_default(heim_context context,
971 const heim_config_section *c,
972 const char *def_value,
973 va_list args)
975 const char *ret;
977 ret = heim_config_vget_string(context, c, args);
978 if (ret == NULL)
979 ret = def_value;
980 return ret;
984 * Like heim_config_get_string(), but instead of returning NULL,
985 * instead return a default value.
987 * @param context A Kerberos 5 context.
988 * @param c a configuration section, or NULL to use the section from context
989 * @param def_value the default value to return if no configuration
990 * found in the database.
991 * @param ... a list of names, terminated with NULL.
993 * @return a configuration string
995 * @ingroup heim_support
998 const char *
999 heim_config_get_string_default(heim_context context,
1000 const heim_config_section *c,
1001 const char *def_value,
1002 ...)
1004 const char *ret;
1005 va_list args;
1007 va_start(args, def_value);
1008 ret = heim_config_vget_string_default (context, c, def_value, args);
1009 va_end(args);
1010 return ret;
1013 static char *
1014 next_component_string(char * begin, const char * delims, char **state)
1016 char * end;
1018 if (begin == NULL)
1019 begin = *state;
1021 if (*begin == '\0')
1022 return NULL;
1024 end = begin;
1025 while (*end == '"') {
1026 char * t = strchr(end + 1, '"');
1028 if (t)
1029 end = ++t;
1030 else
1031 end += strlen(end);
1034 if (*end != '\0') {
1035 size_t pos;
1037 pos = strcspn(end, delims);
1038 end = end + pos;
1041 if (*end != '\0') {
1042 *end = '\0';
1043 *state = end + 1;
1044 if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) {
1045 begin++; *(end - 1) = '\0';
1047 return begin;
1050 *state = end;
1051 if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) {
1052 begin++; *(end - 1) = '\0';
1054 return begin;
1058 * Get a list of configuration strings, free the result with
1059 * heim_config_free_strings().
1061 * @param context A Kerberos 5 context.
1062 * @param c a configuration section, or NULL to use the section from context
1063 * @param args a va_list of arguments
1065 * @return TRUE or FALSE
1067 * @ingroup heim_support
1070 char **
1071 heim_config_vget_strings(heim_context context,
1072 const heim_config_section *c,
1073 va_list args)
1075 char **strings = NULL;
1076 size_t nstr = 0;
1077 const heim_config_binding *b = NULL;
1078 const char *p;
1080 while((p = heim_config_vget_next(context, c, &b,
1081 heim_config_string, args))) {
1082 char *tmp = strdup(p);
1083 char *pos = NULL;
1084 char *s;
1085 if(tmp == NULL)
1086 goto cleanup;
1087 s = next_component_string(tmp, " \t", &pos);
1088 while(s){
1089 char **tmp2 = realloc(strings, (nstr + 1) * sizeof(*strings));
1090 if(tmp2 == NULL) {
1091 free(tmp);
1092 goto cleanup;
1094 strings = tmp2;
1095 strings[nstr] = strdup(s);
1096 nstr++;
1097 if(strings[nstr-1] == NULL) {
1098 free(tmp);
1099 goto cleanup;
1101 s = next_component_string(NULL, " \t", &pos);
1103 free(tmp);
1105 if(nstr){
1106 char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings));
1107 if(tmp == NULL)
1108 goto cleanup;
1109 strings = tmp;
1110 strings[nstr] = NULL;
1112 return strings;
1113 cleanup:
1114 while(nstr--)
1115 free(strings[nstr]);
1116 free(strings);
1117 return NULL;
1122 * Get a list of configuration strings, free the result with
1123 * heim_config_free_strings().
1125 * @param context A Kerberos 5 context.
1126 * @param c a configuration section, or NULL to use the section from context
1127 * @param ... a list of names, terminated with NULL.
1129 * @return TRUE or FALSE
1131 * @ingroup heim_support
1134 char **
1135 heim_config_get_strings(heim_context context,
1136 const heim_config_section *c,
1137 ...)
1139 va_list ap;
1140 char **ret;
1141 va_start(ap, c);
1142 ret = heim_config_vget_strings(context, c, ap);
1143 va_end(ap);
1144 return ret;
1148 * Free the resulting strings from heim_config-get_strings() and
1149 * heim_config_vget_strings().
1151 * @param strings strings to free
1153 * @ingroup heim_support
1156 void
1157 heim_config_free_strings(char **strings)
1159 char **s = strings;
1161 while (s && *s) {
1162 free(*s);
1163 s++;
1165 free(strings);
1169 * Like heim_config_get_bool_default() but with a va_list list of
1170 * configuration selection.
1172 * Configuration value to a boolean value, where yes/true and any
1173 * non-zero number means TRUE and other value is FALSE.
1175 * @param context A Kerberos 5 context.
1176 * @param c a configuration section, or NULL to use the section from context
1177 * @param def_value the default value to return if no configuration
1178 * found in the database.
1179 * @param args a va_list of arguments
1181 * @return TRUE or FALSE
1183 * @ingroup heim_support
1187 heim_config_vget_bool_default(heim_context context,
1188 const heim_config_section *c,
1189 int def_value,
1190 va_list args)
1192 const char *str;
1193 str = heim_config_vget_string(context, c, args);
1194 if (str == NULL)
1195 return def_value;
1196 return !!(strcasecmp(str, "yes") == 0 ||
1197 strcasecmp(str, "true") == 0 ||
1198 atoi(str));
1202 * heim_config_get_bool() will convert the configuration
1203 * option value to a boolean value, where yes/true and any non-zero
1204 * number means TRUE and other value is FALSE.
1206 * @param context A Kerberos 5 context.
1207 * @param c a configuration section, or NULL to use the section from context
1208 * @param args a va_list of arguments
1210 * @return TRUE or FALSE
1212 * @ingroup heim_support
1216 heim_config_vget_bool(heim_context context,
1217 const heim_config_section *c,
1218 va_list args)
1220 return heim_config_vget_bool_default(context, c, 0, args);
1224 * heim_config_get_bool_default() will convert the configuration
1225 * option value to a boolean value, where yes/true and any non-zero
1226 * number means TRUE and other value is FALSE.
1228 * @param context A Kerberos 5 context.
1229 * @param c a configuration section, or NULL to use the section from context
1230 * @param def_value the default value to return if no configuration
1231 * found in the database.
1232 * @param ... a list of names, terminated with NULL.
1234 * @return TRUE or FALSE
1236 * @ingroup heim_support
1240 heim_config_get_bool_default(heim_context context,
1241 const heim_config_section *c,
1242 int def_value,
1243 ...)
1245 va_list ap;
1246 int ret;
1248 va_start(ap, def_value);
1249 ret = heim_config_vget_bool_default(context, c, def_value, ap);
1250 va_end(ap);
1251 return ret;
1255 * Like heim_config_get_bool() but with a va_list list of
1256 * configuration selection.
1258 * Configuration value to a boolean value, where yes/true and any
1259 * non-zero number means TRUE and other value is FALSE.
1261 * @param context A Kerberos 5 context.
1262 * @param c a configuration section, or NULL to use the section from context
1263 * @param ... a list of names, terminated with NULL.
1265 * @return TRUE or FALSE
1267 * @ingroup heim_support
1271 heim_config_get_bool(heim_context context,
1272 const heim_config_section *c,
1273 ...)
1275 va_list ap;
1276 int ret;
1277 va_start(ap, c);
1278 ret = heim_config_vget_bool (context, c, ap);
1279 va_end(ap);
1280 return ret;
1284 * Get the time from the configuration file using a relative time.
1286 * Like heim_config_get_time_default() but with a va_list list of
1287 * configuration selection.
1289 * @param context A Kerberos 5 context.
1290 * @param c a configuration section, or NULL to use the section from context
1291 * @param def_value the default value to return if no configuration
1292 * found in the database.
1293 * @param args a va_list of arguments
1295 * @return parsed the time (or def_value on parse error)
1297 * @ingroup heim_support
1300 time_t
1301 heim_config_vget_time_default(heim_context context,
1302 const heim_config_section *c,
1303 int def_value,
1304 va_list args)
1306 const char *str;
1307 time_t t = -1;
1309 if ((str = heim_config_vget_string(context, c, args)))
1310 t = parse_time(str, "s");
1311 return t != -1 ? t : def_value;
1315 * Get the time from the configuration file using a relative time, for example: 1h30s
1317 * @param context A Kerberos 5 context.
1318 * @param c a configuration section, or NULL to use the section from context
1319 * @param args a va_list of arguments
1321 * @return parsed the time or -1 on error
1323 * @ingroup heim_support
1326 time_t
1327 heim_config_vget_time(heim_context context,
1328 const heim_config_section *c,
1329 va_list args)
1331 return heim_config_vget_time_default(context, c, -1, args);
1335 * Get the time from the configuration file using a relative time, for example: 1h30s
1337 * @param context A Kerberos 5 context.
1338 * @param c a configuration section, or NULL to use the section from context
1339 * @param def_value the default value to return if no configuration
1340 * found in the database.
1341 * @param ... a list of names, terminated with NULL.
1343 * @return parsed the time (or def_value on parse error)
1345 * @ingroup heim_support
1348 time_t
1349 heim_config_get_time_default(heim_context context,
1350 const heim_config_section *c,
1351 int def_value,
1352 ...)
1354 va_list ap;
1355 time_t ret;
1357 va_start(ap, def_value);
1358 ret = heim_config_vget_time_default(context, c, def_value, ap);
1359 va_end(ap);
1360 return ret;
1364 * Get the time from the configuration file using a relative time, for example: 1h30s
1366 * @param context A Kerberos 5 context.
1367 * @param c a configuration section, or NULL to use the section from context
1368 * @param ... a list of names, terminated with NULL.
1370 * @return parsed the time or -1 on error
1372 * @ingroup heim_support
1375 time_t
1376 heim_config_get_time(heim_context context,
1377 const heim_config_section *c,
1378 ...)
1380 va_list ap;
1381 int ret;
1382 va_start(ap, c);
1383 ret = heim_config_vget_time(context, c, ap);
1384 va_end(ap);
1385 return ret;
1390 heim_config_vget_int_default(heim_context context,
1391 const heim_config_section *c,
1392 int def_value,
1393 va_list args)
1395 const char *str;
1396 str = heim_config_vget_string (context, c, args);
1397 if(str == NULL)
1398 return def_value;
1399 else {
1400 char *endptr;
1401 long l;
1402 l = strtol(str, &endptr, 0);
1403 if (endptr == str)
1404 return def_value;
1405 else
1406 return l;
1411 heim_config_vget_int(heim_context context,
1412 const heim_config_section *c,
1413 va_list args)
1415 return heim_config_vget_int_default(context, c, -1, args);
1419 heim_config_get_int_default(heim_context context,
1420 const heim_config_section *c,
1421 int def_value,
1422 ...)
1424 va_list ap;
1425 int ret;
1427 va_start(ap, def_value);
1428 ret = heim_config_vget_int_default(context, c, def_value, ap);
1429 va_end(ap);
1430 return ret;
1434 heim_config_get_int(heim_context context,
1435 const heim_config_section *c,
1436 ...)
1438 va_list ap;
1439 int ret;
1440 va_start(ap, c);
1441 ret = heim_config_vget_int (context, c, ap);
1442 va_end(ap);
1443 return ret;
1446 #ifndef HEIMDAL_SMALLER
1447 heim_error_code
1448 heim_config_parse_string_multi(heim_context context,
1449 const char *string,
1450 heim_config_section **res)
1452 const char *str;
1453 unsigned lineno = 0;
1454 heim_error_code ret;
1455 struct fileptr f;
1457 f.context = context;
1458 f.f = NULL;
1459 f.s = string;
1461 ret = heim_config_parse_debug(&f, res, &lineno, &str);
1462 if (ret) {
1463 if (ret != HEIM_ERR_CONFIG_BADFORMAT) {
1464 ret = HEIM_ERR_CONFIG_BADFORMAT;
1465 heim_set_error_message(context, ret, "%s:%u: %s",
1466 "<constant>", lineno, str);
1468 return ret;
1470 return 0;
1472 #endif