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