155682Smarkm/*
2233294Sstas * Copyright (c) 1997 - 2004 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
755682Smarkm *
8233294Sstas * Redistribution and use in source and binary forms, with or without
9233294Sstas * modification, are permitted provided that the following conditions
10233294Sstas * are met:
1155682Smarkm *
12233294Sstas * 1. Redistributions of source code must retain the above copyright
13233294Sstas *    notice, this list of conditions and the following disclaimer.
1455682Smarkm *
15233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
16233294Sstas *    notice, this list of conditions and the following disclaimer in the
17233294Sstas *    documentation and/or other materials provided with the distribution.
1855682Smarkm *
19233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
20233294Sstas *    may be used to endorse or promote products derived from this software
21233294Sstas *    without specific prior written permission.
22233294Sstas *
23233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33233294Sstas * SUCH DAMAGE.
3455682Smarkm */
3555682Smarkm
3655682Smarkm#include "krb5_locl.h"
3755682Smarkm
38233294Sstas#ifdef __APPLE__
39233294Sstas#include <CoreFoundation/CoreFoundation.h>
40233294Sstas#endif
4155682Smarkm
42178825Sdfr/* Gaah! I want a portable funopen */
43178825Sdfrstruct fileptr {
44178825Sdfr    const char *s;
45178825Sdfr    FILE *f;
46178825Sdfr};
47178825Sdfr
48178825Sdfrstatic char *
49178825Sdfrconfig_fgets(char *str, size_t len, struct fileptr *ptr)
50178825Sdfr{
51178825Sdfr    /* XXX this is not correct, in that they don't do the same if the
52178825Sdfr       line is longer than len */
53178825Sdfr    if(ptr->f != NULL)
54178825Sdfr	return fgets(str, len, ptr->f);
55178825Sdfr    else {
56178825Sdfr	/* this is almost strsep_copy */
57178825Sdfr	const char *p;
58178825Sdfr	ssize_t l;
59178825Sdfr	if(*ptr->s == '\0')
60178825Sdfr	    return NULL;
61178825Sdfr	p = ptr->s + strcspn(ptr->s, "\n");
62178825Sdfr	if(*p == '\n')
63178825Sdfr	    p++;
64233294Sstas	l = min(len, (size_t)(p - ptr->s));
65178825Sdfr	if(len > 0) {
66178825Sdfr	    memcpy(str, ptr->s, l);
67178825Sdfr	    str[l] = '\0';
68178825Sdfr	}
69178825Sdfr	ptr->s = p;
70178825Sdfr	return str;
71178825Sdfr    }
72178825Sdfr}
73178825Sdfr
7478527Sassarstatic krb5_error_code parse_section(char *p, krb5_config_section **s,
7578527Sassar				     krb5_config_section **res,
76233294Sstas				     const char **err_message);
77178825Sdfrstatic krb5_error_code parse_binding(struct fileptr *f, unsigned *lineno, char *p,
7878527Sassar				     krb5_config_binding **b,
7978527Sassar				     krb5_config_binding **parent,
80233294Sstas				     const char **err_message);
81178825Sdfrstatic krb5_error_code parse_list(struct fileptr *f, unsigned *lineno,
8278527Sassar				  krb5_config_binding **parent,
83233294Sstas				  const char **err_message);
8455682Smarkm
85233294Sstaskrb5_config_section *
86233294Sstas_krb5_config_get_entry(krb5_config_section **parent, const char *name, int type)
87102644Snectar{
88102644Snectar    krb5_config_section **q;
89102644Snectar
90102644Snectar    for(q = parent; *q != NULL; q = &(*q)->next)
91233294Sstas	if(type == krb5_config_list &&
92233294Sstas	   (unsigned)type == (*q)->type &&
93102644Snectar	   strcmp(name, (*q)->name) == 0)
94102644Snectar	    return *q;
95102644Snectar    *q = calloc(1, sizeof(**q));
96102644Snectar    if(*q == NULL)
97102644Snectar	return NULL;
98102644Snectar    (*q)->name = strdup(name);
99102644Snectar    (*q)->type = type;
100102644Snectar    if((*q)->name == NULL) {
101102644Snectar	free(*q);
102102644Snectar	*q = NULL;
103102644Snectar	return NULL;
104102644Snectar    }
105102644Snectar    return *q;
106102644Snectar}
107102644Snectar
10855682Smarkm/*
10955682Smarkm * Parse a section:
11055682Smarkm *
11155682Smarkm * [section]
11255682Smarkm *	foo = bar
11355682Smarkm *	b = {
11455682Smarkm *		a
11555682Smarkm *	    }
11655682Smarkm * ...
117233294Sstas *
11855682Smarkm * starting at the line in `p', storing the resulting structure in
11955682Smarkm * `s' and hooking it into `parent'.
120233294Sstas * Store the error message in `err_message'.
12155682Smarkm */
12255682Smarkm
12378527Sassarstatic krb5_error_code
12455682Smarkmparse_section(char *p, krb5_config_section **s, krb5_config_section **parent,
125233294Sstas	      const char **err_message)
12655682Smarkm{
12755682Smarkm    char *p1;
12855682Smarkm    krb5_config_section *tmp;
12955682Smarkm
13055682Smarkm    p1 = strchr (p + 1, ']');
13155682Smarkm    if (p1 == NULL) {
132233294Sstas	*err_message = "missing ]";
13378527Sassar	return KRB5_CONFIG_BADFORMAT;
13455682Smarkm    }
13555682Smarkm    *p1 = '\0';
136233294Sstas    tmp = _krb5_config_get_entry(parent, p + 1, krb5_config_list);
137102644Snectar    if(tmp == NULL) {
138233294Sstas	*err_message = "out of memory";
13978527Sassar	return KRB5_CONFIG_BADFORMAT;
14055682Smarkm    }
14155682Smarkm    *s = tmp;
14255682Smarkm    return 0;
14355682Smarkm}
14455682Smarkm
14555682Smarkm/*
14655682Smarkm * Parse a brace-enclosed list from `f', hooking in the structure at
14755682Smarkm * `parent'.
148233294Sstas * Store the error message in `err_message'.
14955682Smarkm */
15055682Smarkm
151127808Snectarstatic krb5_error_code
152178825Sdfrparse_list(struct fileptr *f, unsigned *lineno, krb5_config_binding **parent,
153233294Sstas	   const char **err_message)
15455682Smarkm{
155233294Sstas    char buf[KRB5_BUFSIZ];
156127808Snectar    krb5_error_code ret;
15755682Smarkm    krb5_config_binding *b = NULL;
15855682Smarkm    unsigned beg_lineno = *lineno;
15955682Smarkm
160178825Sdfr    while(config_fgets(buf, sizeof(buf), f) != NULL) {
16155682Smarkm	char *p;
16255682Smarkm
16355682Smarkm	++*lineno;
164178825Sdfr	buf[strcspn(buf, "\r\n")] = '\0';
16555682Smarkm	p = buf;
16655682Smarkm	while(isspace((unsigned char)*p))
16755682Smarkm	    ++p;
16855682Smarkm	if (*p == '#' || *p == ';' || *p == '\0')
16955682Smarkm	    continue;
17055682Smarkm	while(isspace((unsigned char)*p))
17155682Smarkm	    ++p;
17255682Smarkm	if (*p == '}')
17355682Smarkm	    return 0;
17455682Smarkm	if (*p == '\0')
17555682Smarkm	    continue;
176233294Sstas	ret = parse_binding (f, lineno, p, &b, parent, err_message);
17755682Smarkm	if (ret)
17855682Smarkm	    return ret;
17955682Smarkm    }
18055682Smarkm    *lineno = beg_lineno;
181233294Sstas    *err_message = "unclosed {";
18278527Sassar    return KRB5_CONFIG_BADFORMAT;
18355682Smarkm}
18455682Smarkm
18555682Smarkm/*
18655682Smarkm *
18755682Smarkm */
18855682Smarkm
189127808Snectarstatic krb5_error_code
190178825Sdfrparse_binding(struct fileptr *f, unsigned *lineno, char *p,
19155682Smarkm	      krb5_config_binding **b, krb5_config_binding **parent,
192233294Sstas	      const char **err_message)
19355682Smarkm{
19455682Smarkm    krb5_config_binding *tmp;
19555682Smarkm    char *p1, *p2;
196127808Snectar    krb5_error_code ret = 0;
19755682Smarkm
19855682Smarkm    p1 = p;
19955682Smarkm    while (*p && *p != '=' && !isspace((unsigned char)*p))
20055682Smarkm	++p;
20155682Smarkm    if (*p == '\0') {
202233294Sstas	*err_message = "missing =";
20378527Sassar	return KRB5_CONFIG_BADFORMAT;
20455682Smarkm    }
20555682Smarkm    p2 = p;
20655682Smarkm    while (isspace((unsigned char)*p))
20755682Smarkm	++p;
20855682Smarkm    if (*p != '=') {
209233294Sstas	*err_message = "missing =";
21078527Sassar	return KRB5_CONFIG_BADFORMAT;
21155682Smarkm    }
21255682Smarkm    ++p;
21355682Smarkm    while(isspace((unsigned char)*p))
21455682Smarkm	++p;
21555682Smarkm    *p2 = '\0';
21655682Smarkm    if (*p == '{') {
217233294Sstas	tmp = _krb5_config_get_entry(parent, p1, krb5_config_list);
218102644Snectar	if (tmp == NULL) {
219233294Sstas	    *err_message = "out of memory";
220102644Snectar	    return KRB5_CONFIG_BADFORMAT;
221102644Snectar	}
222233294Sstas	ret = parse_list (f, lineno, &tmp->u.list, err_message);
22355682Smarkm    } else {
224233294Sstas	tmp = _krb5_config_get_entry(parent, p1, krb5_config_string);
225102644Snectar	if (tmp == NULL) {
226233294Sstas	    *err_message = "out of memory";
227102644Snectar	    return KRB5_CONFIG_BADFORMAT;
228102644Snectar	}
22955682Smarkm	p1 = p;
23055682Smarkm	p = p1 + strlen(p1);
23155682Smarkm	while(p > p1 && isspace((unsigned char)*(p-1)))
23255682Smarkm	    --p;
23355682Smarkm	*p = '\0';
23455682Smarkm	tmp->u.string = strdup(p1);
23555682Smarkm    }
23655682Smarkm    *b = tmp;
23755682Smarkm    return ret;
23855682Smarkm}
23955682Smarkm
240233294Sstas#if defined(__APPLE__)
241233294Sstas
242233294Sstas#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
243233294Sstas#define HAVE_CFPROPERTYLISTCREATEWITHSTREAM 1
244233294Sstas#endif
245233294Sstas
246233294Sstasstatic char *
247233294Sstascfstring2cstring(CFStringRef string)
248233294Sstas{
249233294Sstas    CFIndex len;
250233294Sstas    char *str;
251233294Sstas
252233294Sstas    str = (char *) CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
253233294Sstas    if (str)
254233294Sstas	return strdup(str);
255233294Sstas
256233294Sstas    len = CFStringGetLength(string);
257233294Sstas    len = 1 + CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8);
258233294Sstas    str = malloc(len);
259233294Sstas    if (str == NULL)
260233294Sstas	return NULL;
261233294Sstas
262233294Sstas    if (!CFStringGetCString (string, str, len, kCFStringEncodingUTF8)) {
263233294Sstas	free (str);
264233294Sstas	return NULL;
265233294Sstas    }
266233294Sstas    return str;
267233294Sstas}
268233294Sstas
269233294Sstasstatic void
270233294Sstasconvert_content(const void *key, const void *value, void *context)
271233294Sstas{
272233294Sstas    krb5_config_section *tmp, **parent = context;
273233294Sstas    char *k;
274233294Sstas
275233294Sstas    if (CFGetTypeID(key) != CFStringGetTypeID())
276233294Sstas	return;
277233294Sstas
278233294Sstas    k = cfstring2cstring(key);
279233294Sstas    if (k == NULL)
280233294Sstas	return;
281233294Sstas
282233294Sstas    if (CFGetTypeID(value) == CFStringGetTypeID()) {
283233294Sstas	tmp = _krb5_config_get_entry(parent, k, krb5_config_string);
284233294Sstas	tmp->u.string = cfstring2cstring(value);
285233294Sstas    } else if (CFGetTypeID(value) == CFDictionaryGetTypeID()) {
286233294Sstas	tmp = _krb5_config_get_entry(parent, k, krb5_config_list);
287233294Sstas	CFDictionaryApplyFunction(value, convert_content, &tmp->u.list);
288233294Sstas    } else {
289233294Sstas	/* log */
290233294Sstas    }
291233294Sstas    free(k);
292233294Sstas}
293233294Sstas
294233294Sstasstatic krb5_error_code
295233294Sstasparse_plist_config(krb5_context context, const char *path, krb5_config_section **parent)
296233294Sstas{
297233294Sstas    CFReadStreamRef s;
298233294Sstas    CFDictionaryRef d;
299233294Sstas    CFURLRef url;
300233294Sstas
301233294Sstas    url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)path, strlen(path), FALSE);
302233294Sstas    if (url == NULL) {
303233294Sstas	krb5_clear_error_message(context);
304233294Sstas	return ENOMEM;
305233294Sstas    }
306233294Sstas
307233294Sstas    s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
308233294Sstas    CFRelease(url);
309233294Sstas    if (s == NULL) {
310233294Sstas	krb5_clear_error_message(context);
311233294Sstas	return ENOMEM;
312233294Sstas    }
313233294Sstas
314233294Sstas    if (!CFReadStreamOpen(s)) {
315233294Sstas	CFRelease(s);
316233294Sstas	krb5_clear_error_message(context);
317233294Sstas	return ENOENT;
318233294Sstas    }
319233294Sstas
320233294Sstas#ifdef HAVE_CFPROPERTYLISTCREATEWITHSTREAM
321233294Sstas    d = (CFDictionaryRef)CFPropertyListCreateWithStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL);
322233294Sstas#else
323233294Sstas    d = (CFDictionaryRef)CFPropertyListCreateFromStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL);
324233294Sstas#endif
325233294Sstas    CFRelease(s);
326233294Sstas    if (d == NULL) {
327233294Sstas	krb5_clear_error_message(context);
328233294Sstas	return ENOENT;
329233294Sstas    }
330233294Sstas
331233294Sstas    CFDictionaryApplyFunction(d, convert_content, parent);
332233294Sstas    CFRelease(d);
333233294Sstas
334233294Sstas    return 0;
335233294Sstas}
336233294Sstas
337233294Sstas#endif
338233294Sstas
339233294Sstas
34055682Smarkm/*
34155682Smarkm * Parse the config file `fname', generating the structures into `res'
342233294Sstas * returning error messages in `err_message'
34355682Smarkm */
34455682Smarkm
34578527Sassarstatic krb5_error_code
346178825Sdfrkrb5_config_parse_debug (struct fileptr *f,
347178825Sdfr			 krb5_config_section **res,
348178825Sdfr			 unsigned *lineno,
349233294Sstas			 const char **err_message)
35055682Smarkm{
351178825Sdfr    krb5_config_section *s = NULL;
352178825Sdfr    krb5_config_binding *b = NULL;
353233294Sstas    char buf[KRB5_BUFSIZ];
354178825Sdfr    krb5_error_code ret;
35555682Smarkm
356178825Sdfr    while (config_fgets(buf, sizeof(buf), f) != NULL) {
35755682Smarkm	char *p;
35855682Smarkm
35955682Smarkm	++*lineno;
360178825Sdfr	buf[strcspn(buf, "\r\n")] = '\0';
36155682Smarkm	p = buf;
36255682Smarkm	while(isspace((unsigned char)*p))
36355682Smarkm	    ++p;
36455682Smarkm	if (*p == '#' || *p == ';')
36555682Smarkm	    continue;
36655682Smarkm	if (*p == '[') {
367233294Sstas	    ret = parse_section(p, &s, res, err_message);
368233294Sstas	    if (ret)
369178825Sdfr		return ret;
37055682Smarkm	    b = NULL;
37155682Smarkm	} else if (*p == '}') {
372233294Sstas	    *err_message = "unmatched }";
373178825Sdfr	    return EINVAL;	/* XXX */
37455682Smarkm	} else if(*p != '\0') {
375127808Snectar	    if (s == NULL) {
376233294Sstas		*err_message = "binding before section";
377178825Sdfr		return EINVAL;
378127808Snectar	    }
379233294Sstas	    ret = parse_binding(f, lineno, p, &b, &s->u.list, err_message);
38055682Smarkm	    if (ret)
381178825Sdfr		return ret;
38255682Smarkm	}
38355682Smarkm    }
384178825Sdfr    return 0;
38555682Smarkm}
38655682Smarkm
387233294Sstasstatic int
388233294Sstasis_plist_file(const char *fname)
389178825Sdfr{
390233294Sstas    size_t len = strlen(fname);
391233294Sstas    char suffix[] = ".plist";
392233294Sstas    if (len < sizeof(suffix))
393233294Sstas	return 0;
394233294Sstas    if (strcasecmp(&fname[len - (sizeof(suffix) - 1)], suffix) != 0)
395233294Sstas	return 0;
396233294Sstas    return 1;
397178825Sdfr}
398178825Sdfr
399233294Sstas/**
400233294Sstas * Parse a configuration file and add the result into res. This
401233294Sstas * interface can be used to parse several configuration files into one
402233294Sstas * resulting krb5_config_section by calling it repeatably.
403233294Sstas *
404233294Sstas * @param context a Kerberos 5 context.
405233294Sstas * @param fname a file name to a Kerberos configuration file
406233294Sstas * @param res the returned result, must be free with krb5_free_config_files().
407233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
408233294Sstas *
409233294Sstas * @ingroup krb5_support
410233294Sstas */
411233294Sstas
412233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
413102644Snectarkrb5_config_parse_file_multi (krb5_context context,
414102644Snectar			      const char *fname,
415102644Snectar			      krb5_config_section **res)
41655682Smarkm{
417102644Snectar    const char *str;
418233294Sstas    char *newfname = NULL;
419178825Sdfr    unsigned lineno = 0;
42078527Sassar    krb5_error_code ret;
421178825Sdfr    struct fileptr f;
422233294Sstas
423233294Sstas    /**
424233294Sstas     * If the fname starts with "~/" parse configuration file in the
425233294Sstas     * current users home directory. The behavior can be disabled and
426233294Sstas     * enabled by calling krb5_set_home_dir_access().
427233294Sstas     */
428233294Sstas    if (fname[0] == '~' && fname[1] == '/') {
429233294Sstas#ifndef KRB5_USE_PATH_TOKENS
430233294Sstas	const char *home = NULL;
431233294Sstas
432233294Sstas	if (!_krb5_homedir_access(context)) {
433233294Sstas	    krb5_set_error_message(context, EPERM,
434233294Sstas				   "Access to home directory not allowed");
435233294Sstas	    return EPERM;
436233294Sstas	}
437233294Sstas
438233294Sstas	if(!issuid())
439233294Sstas	    home = getenv("HOME");
440233294Sstas
441233294Sstas	if (home == NULL) {
442233294Sstas	    struct passwd *pw = getpwuid(getuid());
443233294Sstas	    if(pw != NULL)
444233294Sstas		home = pw->pw_dir;
445233294Sstas	}
446233294Sstas	if (home) {
447233294Sstas	    asprintf(&newfname, "%s%s", home, &fname[1]);
448233294Sstas	    if (newfname == NULL) {
449233294Sstas		krb5_set_error_message(context, ENOMEM,
450233294Sstas				       N_("malloc: out of memory", ""));
451233294Sstas		return ENOMEM;
452233294Sstas	    }
453233294Sstas	    fname = newfname;
454233294Sstas	}
455233294Sstas#else  /* KRB5_USE_PATH_TOKENS */
456233294Sstas	if (asprintf(&newfname, "%%{USERCONFIG}%s", &fname[1]) < 0 ||
457233294Sstas	    newfname == NULL)
458233294Sstas	{
459233294Sstas	    krb5_set_error_message(context, ENOMEM,
460233294Sstas				   N_("malloc: out of memory", ""));
461233294Sstas	    return ENOMEM;
462233294Sstas	}
463233294Sstas	fname = newfname;
464233294Sstas#endif
465178825Sdfr    }
46655682Smarkm
467233294Sstas    if (is_plist_file(fname)) {
468233294Sstas#ifdef __APPLE__
469233294Sstas	ret = parse_plist_config(context, fname, res);
470233294Sstas	if (ret) {
471233294Sstas	    krb5_set_error_message(context, ret,
472233294Sstas				   "Failed to parse plist %s", fname);
473233294Sstas	    if (newfname)
474233294Sstas		free(newfname);
475233294Sstas	    return ret;
476233294Sstas	}
477233294Sstas#else
478233294Sstas	krb5_set_error_message(context, ENOENT,
479233294Sstas			       "no support for plist configuration files");
480233294Sstas	return ENOENT;
481233294Sstas#endif
482233294Sstas    } else {
483233294Sstas#ifdef KRB5_USE_PATH_TOKENS
484233294Sstas	char * exp_fname = NULL;
485233294Sstas
486233294Sstas	ret = _krb5_expand_path_tokens(context, fname, &exp_fname);
487233294Sstas	if (ret) {
488233294Sstas	    if (newfname)
489233294Sstas		free(newfname);
490233294Sstas	    return ret;
491233294Sstas	}
492233294Sstas
493233294Sstas	if (newfname)
494233294Sstas	    free(newfname);
495233294Sstas	fname = newfname = exp_fname;
496233294Sstas#endif
497233294Sstas
498233294Sstas	f.f = fopen(fname, "r");
499233294Sstas	f.s = NULL;
500233294Sstas	if(f.f == NULL) {
501233294Sstas	    ret = errno;
502233294Sstas	    krb5_set_error_message (context, ret, "open %s: %s",
503233294Sstas				    fname, strerror(ret));
504233294Sstas	    if (newfname)
505233294Sstas		free(newfname);
506233294Sstas	    return ret;
507233294Sstas	}
508233294Sstas
509233294Sstas	ret = krb5_config_parse_debug (&f, res, &lineno, &str);
510233294Sstas	fclose(f.f);
511233294Sstas	if (ret) {
512233294Sstas	    krb5_set_error_message (context, ret, "%s:%u: %s",
513233294Sstas				    fname, lineno, str);
514233294Sstas	    if (newfname)
515233294Sstas		free(newfname);
516233294Sstas	    return ret;
517233294Sstas	}
51878527Sassar    }
51978527Sassar    return 0;
52055682Smarkm}
52155682Smarkm
522233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
523102644Snectarkrb5_config_parse_file (krb5_context context,
524102644Snectar			const char *fname,
525102644Snectar			krb5_config_section **res)
526102644Snectar{
527102644Snectar    *res = NULL;
528102644Snectar    return krb5_config_parse_file_multi(context, fname, res);
529102644Snectar}
530102644Snectar
53155682Smarkmstatic void
53255682Smarkmfree_binding (krb5_context context, krb5_config_binding *b)
53355682Smarkm{
53455682Smarkm    krb5_config_binding *next_b;
53555682Smarkm
53655682Smarkm    while (b) {
53755682Smarkm	free (b->name);
53855682Smarkm	if (b->type == krb5_config_string)
53955682Smarkm	    free (b->u.string);
54055682Smarkm	else if (b->type == krb5_config_list)
54155682Smarkm	    free_binding (context, b->u.list);
54255682Smarkm	else
543233294Sstas	    krb5_abortx(context, "unknown binding type (%d) in free_binding",
54455682Smarkm			b->type);
54555682Smarkm	next_b = b->next;
54655682Smarkm	free (b);
54755682Smarkm	b = next_b;
54855682Smarkm    }
54955682Smarkm}
55055682Smarkm
551233294Sstas/**
552233294Sstas * Free configuration file section, the result of
553233294Sstas * krb5_config_parse_file() and krb5_config_parse_file_multi().
554233294Sstas *
555233294Sstas * @param context A Kerberos 5 context
556233294Sstas * @param s the configuration section to free
557233294Sstas *
558233294Sstas * @return returns 0 on successes, otherwise an error code, see
559233294Sstas *          krb5_get_error_message()
560233294Sstas *
561233294Sstas * @ingroup krb5_support
562233294Sstas */
563233294Sstas
564233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
56555682Smarkmkrb5_config_file_free (krb5_context context, krb5_config_section *s)
56655682Smarkm{
56755682Smarkm    free_binding (context, s);
56855682Smarkm    return 0;
56955682Smarkm}
57055682Smarkm
571233294Sstas#ifndef HEIMDAL_SMALLER
572233294Sstas
573233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
574233294Sstas_krb5_config_copy(krb5_context context,
575233294Sstas		  krb5_config_section *c,
576233294Sstas		  krb5_config_section **head)
57755682Smarkm{
578233294Sstas    krb5_config_binding *d, *previous = NULL;
579233294Sstas
580233294Sstas    *head = NULL;
581233294Sstas
582233294Sstas    while (c) {
583233294Sstas	d = calloc(1, sizeof(*d));
584233294Sstas
585233294Sstas	if (*head == NULL)
586233294Sstas	    *head = d;
587233294Sstas
588233294Sstas	d->name = strdup(c->name);
589233294Sstas	d->type = c->type;
590233294Sstas	if (d->type == krb5_config_string)
591233294Sstas	    d->u.string = strdup(c->u.string);
592233294Sstas	else if (d->type == krb5_config_list)
593233294Sstas	    _krb5_config_copy (context, c->u.list, &d->u.list);
594233294Sstas	else
595233294Sstas	    krb5_abortx(context,
596233294Sstas			"unknown binding type (%d) in krb5_config_copy",
597233294Sstas			d->type);
598233294Sstas	if (previous)
599233294Sstas	    previous->next = d;
600233294Sstas
601233294Sstas	previous = d;
602233294Sstas	c = c->next;
603233294Sstas    }
604233294Sstas    return 0;
605233294Sstas}
606233294Sstas
607233294Sstas#endif /* HEIMDAL_SMALLER */
608233294Sstas
609233294SstasKRB5_LIB_FUNCTION const void * KRB5_LIB_CALL
610233294Sstas_krb5_config_get_next (krb5_context context,
611233294Sstas		       const krb5_config_section *c,
612233294Sstas		       const krb5_config_binding **pointer,
613233294Sstas		       int type,
614233294Sstas		       ...)
615233294Sstas{
61655682Smarkm    const char *ret;
61755682Smarkm    va_list args;
61855682Smarkm
61955682Smarkm    va_start(args, type);
620233294Sstas    ret = _krb5_config_vget_next (context, c, pointer, type, args);
62155682Smarkm    va_end(args);
62255682Smarkm    return ret;
62355682Smarkm}
62455682Smarkm
625102644Snectarstatic const void *
626102644Snectarvget_next(krb5_context context,
627102644Snectar	  const krb5_config_binding *b,
628102644Snectar	  const krb5_config_binding **pointer,
629102644Snectar	  int type,
630102644Snectar	  const char *name,
631102644Snectar	  va_list args)
632102644Snectar{
633102644Snectar    const char *p = va_arg(args, const char *);
634102644Snectar    while(b != NULL) {
635103423Snectar	if(strcmp(b->name, name) == 0) {
636233294Sstas	    if(b->type == (unsigned)type && p == NULL) {
637102644Snectar		*pointer = b;
638102644Snectar		return b->u.generic;
639102644Snectar	    } else if(b->type == krb5_config_list && p != NULL) {
640102644Snectar		return vget_next(context, b->u.list, pointer, type, p, args);
641102644Snectar	    }
642102644Snectar	}
643102644Snectar	b = b->next;
644102644Snectar    }
645102644Snectar    return NULL;
646102644Snectar}
647102644Snectar
648233294SstasKRB5_LIB_FUNCTION const void * KRB5_LIB_CALL
649233294Sstas_krb5_config_vget_next (krb5_context context,
650233294Sstas			const krb5_config_section *c,
651233294Sstas			const krb5_config_binding **pointer,
652233294Sstas			int type,
653233294Sstas			va_list args)
65455682Smarkm{
655102644Snectar    const krb5_config_binding *b;
65655682Smarkm    const char *p;
65755682Smarkm
65855682Smarkm    if(c == NULL)
65955682Smarkm	c = context->cf;
66055682Smarkm
66155682Smarkm    if (c == NULL)
66255682Smarkm	return NULL;
66355682Smarkm
66455682Smarkm    if (*pointer == NULL) {
665102644Snectar	/* first time here, walk down the tree looking for the right
666102644Snectar           section */
66755682Smarkm	p = va_arg(args, const char *);
66855682Smarkm	if (p == NULL)
66955682Smarkm	    return NULL;
670102644Snectar	return vget_next(context, c, pointer, type, p, args);
67155682Smarkm    }
67255682Smarkm
673102644Snectar    /* we were called again, so just look for more entries with the
674102644Snectar       same name and type */
675102644Snectar    for (b = (*pointer)->next; b != NULL; b = b->next) {
676233294Sstas	if(strcmp(b->name, (*pointer)->name) == 0 && b->type == (unsigned)type) {
677102644Snectar	    *pointer = b;
678102644Snectar	    return b->u.generic;
67955682Smarkm	}
68055682Smarkm    }
68155682Smarkm    return NULL;
68255682Smarkm}
68355682Smarkm
684233294SstasKRB5_LIB_FUNCTION const void * KRB5_LIB_CALL
685233294Sstas_krb5_config_get (krb5_context context,
686233294Sstas		  const krb5_config_section *c,
687233294Sstas		  int type,
688233294Sstas		  ...)
68955682Smarkm{
69055682Smarkm    const void *ret;
69155682Smarkm    va_list args;
69255682Smarkm
69355682Smarkm    va_start(args, type);
694233294Sstas    ret = _krb5_config_vget (context, c, type, args);
69555682Smarkm    va_end(args);
69655682Smarkm    return ret;
69755682Smarkm}
69855682Smarkm
699233294Sstas
70055682Smarkmconst void *
701233294Sstas_krb5_config_vget (krb5_context context,
702233294Sstas		   const krb5_config_section *c,
703233294Sstas		   int type,
704233294Sstas		   va_list args)
70555682Smarkm{
706102644Snectar    const krb5_config_binding *foo = NULL;
70755682Smarkm
708233294Sstas    return _krb5_config_vget_next (context, c, &foo, type, args);
70955682Smarkm}
71055682Smarkm
711233294Sstas/**
712233294Sstas * Get a list of configuration binding list for more processing
713233294Sstas *
714233294Sstas * @param context A Kerberos 5 context.
715233294Sstas * @param c a configuration section, or NULL to use the section from context
716233294Sstas * @param ... a list of names, terminated with NULL.
717233294Sstas *
718233294Sstas * @return NULL if configuration list is not found, a list otherwise
719233294Sstas *
720233294Sstas * @ingroup krb5_support
721233294Sstas */
722233294Sstas
723233294SstasKRB5_LIB_FUNCTION const krb5_config_binding * KRB5_LIB_CALL
72455682Smarkmkrb5_config_get_list (krb5_context context,
725102644Snectar		      const krb5_config_section *c,
72655682Smarkm		      ...)
72755682Smarkm{
72855682Smarkm    const krb5_config_binding *ret;
72955682Smarkm    va_list args;
73055682Smarkm
73155682Smarkm    va_start(args, c);
73255682Smarkm    ret = krb5_config_vget_list (context, c, args);
73355682Smarkm    va_end(args);
73455682Smarkm    return ret;
73555682Smarkm}
73655682Smarkm
737233294Sstas/**
738233294Sstas * Get a list of configuration binding list for more processing
739233294Sstas *
740233294Sstas * @param context A Kerberos 5 context.
741233294Sstas * @param c a configuration section, or NULL to use the section from context
742233294Sstas * @param args a va_list of arguments
743233294Sstas *
744233294Sstas * @return NULL if configuration list is not found, a list otherwise
745233294Sstas *
746233294Sstas * @ingroup krb5_support
747233294Sstas */
748233294Sstas
749233294SstasKRB5_LIB_FUNCTION const krb5_config_binding * KRB5_LIB_CALL
75055682Smarkmkrb5_config_vget_list (krb5_context context,
751102644Snectar		       const krb5_config_section *c,
75255682Smarkm		       va_list args)
75355682Smarkm{
754233294Sstas    return _krb5_config_vget (context, c, krb5_config_list, args);
75555682Smarkm}
75655682Smarkm
757233294Sstas/**
758233294Sstas * Returns a "const char *" to a string in the configuration database.
759233294Sstas * The string may not be valid after a reload of the configuration
760233294Sstas * database so a caller should make a local copy if it needs to keep
761233294Sstas * the string.
762233294Sstas *
763233294Sstas * @param context A Kerberos 5 context.
764233294Sstas * @param c a configuration section, or NULL to use the section from context
765233294Sstas * @param ... a list of names, terminated with NULL.
766233294Sstas *
767233294Sstas * @return NULL if configuration string not found, a string otherwise
768233294Sstas *
769233294Sstas * @ingroup krb5_support
770233294Sstas */
771233294Sstas
772233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
77355682Smarkmkrb5_config_get_string (krb5_context context,
774102644Snectar			const krb5_config_section *c,
77555682Smarkm			...)
77655682Smarkm{
77755682Smarkm    const char *ret;
77855682Smarkm    va_list args;
77955682Smarkm
78055682Smarkm    va_start(args, c);
78155682Smarkm    ret = krb5_config_vget_string (context, c, args);
78255682Smarkm    va_end(args);
78355682Smarkm    return ret;
78455682Smarkm}
78555682Smarkm
786233294Sstas/**
787233294Sstas * Like krb5_config_get_string(), but uses a va_list instead of ...
788233294Sstas *
789233294Sstas * @param context A Kerberos 5 context.
790233294Sstas * @param c a configuration section, or NULL to use the section from context
791233294Sstas * @param args a va_list of arguments
792233294Sstas *
793233294Sstas * @return NULL if configuration string not found, a string otherwise
794233294Sstas *
795233294Sstas * @ingroup krb5_support
796233294Sstas */
797233294Sstas
798233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
79955682Smarkmkrb5_config_vget_string (krb5_context context,
800102644Snectar			 const krb5_config_section *c,
80155682Smarkm			 va_list args)
80255682Smarkm{
803233294Sstas    return _krb5_config_vget (context, c, krb5_config_string, args);
80455682Smarkm}
80555682Smarkm
806233294Sstas/**
807233294Sstas * Like krb5_config_vget_string(), but instead of returning NULL,
808233294Sstas * instead return a default value.
809233294Sstas *
810233294Sstas * @param context A Kerberos 5 context.
811233294Sstas * @param c a configuration section, or NULL to use the section from context
812233294Sstas * @param def_value the default value to return if no configuration
813233294Sstas *        found in the database.
814233294Sstas * @param args a va_list of arguments
815233294Sstas *
816233294Sstas * @return a configuration string
817233294Sstas *
818233294Sstas * @ingroup krb5_support
819233294Sstas */
820233294Sstas
821233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
82272445Sassarkrb5_config_vget_string_default (krb5_context context,
823102644Snectar				 const krb5_config_section *c,
82472445Sassar				 const char *def_value,
82572445Sassar				 va_list args)
82672445Sassar{
82772445Sassar    const char *ret;
82872445Sassar
82972445Sassar    ret = krb5_config_vget_string (context, c, args);
83072445Sassar    if (ret == NULL)
83172445Sassar	ret = def_value;
83272445Sassar    return ret;
83372445Sassar}
83472445Sassar
835233294Sstas/**
836233294Sstas * Like krb5_config_get_string(), but instead of returning NULL,
837233294Sstas * instead return a default value.
838233294Sstas *
839233294Sstas * @param context A Kerberos 5 context.
840233294Sstas * @param c a configuration section, or NULL to use the section from context
841233294Sstas * @param def_value the default value to return if no configuration
842233294Sstas *        found in the database.
843233294Sstas * @param ... a list of names, terminated with NULL.
844233294Sstas *
845233294Sstas * @return a configuration string
846233294Sstas *
847233294Sstas * @ingroup krb5_support
848233294Sstas */
849233294Sstas
850233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
85172445Sassarkrb5_config_get_string_default (krb5_context context,
852102644Snectar				const krb5_config_section *c,
85372445Sassar				const char *def_value,
85472445Sassar				...)
85572445Sassar{
85672445Sassar    const char *ret;
85772445Sassar    va_list args;
85872445Sassar
85972445Sassar    va_start(args, def_value);
86072445Sassar    ret = krb5_config_vget_string_default (context, c, def_value, args);
86172445Sassar    va_end(args);
86272445Sassar    return ret;
86372445Sassar}
86472445Sassar
865233294Sstasstatic char *
866233294Sstasnext_component_string(char * begin, const char * delims, char **state)
867233294Sstas{
868233294Sstas    char * end;
869233294Sstas
870233294Sstas    if (begin == NULL)
871233294Sstas        begin = *state;
872233294Sstas
873233294Sstas    if (*begin == '\0')
874233294Sstas        return NULL;
875233294Sstas
876233294Sstas    end = begin;
877233294Sstas    while (*end == '"') {
878233294Sstas        char * t = strchr(end + 1, '"');
879233294Sstas
880233294Sstas        if (t)
881233294Sstas            end = ++t;
882233294Sstas        else
883233294Sstas            end += strlen(end);
884233294Sstas    }
885233294Sstas
886233294Sstas    if (*end != '\0') {
887233294Sstas        size_t pos;
888233294Sstas
889233294Sstas        pos = strcspn(end, delims);
890233294Sstas        end = end + pos;
891233294Sstas    }
892233294Sstas
893233294Sstas    if (*end != '\0') {
894233294Sstas        *end = '\0';
895233294Sstas        *state = end + 1;
896233294Sstas        if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) {
897233294Sstas            begin++; *(end - 1) = '\0';
898233294Sstas        }
899233294Sstas        return begin;
900233294Sstas    }
901233294Sstas
902233294Sstas    *state = end;
903233294Sstas    if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) {
904233294Sstas        begin++; *(end - 1) = '\0';
905233294Sstas    }
906233294Sstas    return begin;
907233294Sstas}
908233294Sstas
909233294Sstas/**
910233294Sstas * Get a list of configuration strings, free the result with
911233294Sstas * krb5_config_free_strings().
912233294Sstas *
913233294Sstas * @param context A Kerberos 5 context.
914233294Sstas * @param c a configuration section, or NULL to use the section from context
915233294Sstas * @param args a va_list of arguments
916233294Sstas *
917233294Sstas * @return TRUE or FALSE
918233294Sstas *
919233294Sstas * @ingroup krb5_support
920233294Sstas */
921233294Sstas
922233294SstasKRB5_LIB_FUNCTION char ** KRB5_LIB_CALL
92355682Smarkmkrb5_config_vget_strings(krb5_context context,
924102644Snectar			 const krb5_config_section *c,
92555682Smarkm			 va_list args)
92655682Smarkm{
92755682Smarkm    char **strings = NULL;
92855682Smarkm    int nstr = 0;
929102644Snectar    const krb5_config_binding *b = NULL;
93055682Smarkm    const char *p;
93155682Smarkm
932233294Sstas    while((p = _krb5_config_vget_next(context, c, &b,
933233294Sstas				      krb5_config_string, args))) {
93455682Smarkm	char *tmp = strdup(p);
93555682Smarkm	char *pos = NULL;
93655682Smarkm	char *s;
93755682Smarkm	if(tmp == NULL)
93855682Smarkm	    goto cleanup;
939233294Sstas	s = next_component_string(tmp, " \t", &pos);
94055682Smarkm	while(s){
941178825Sdfr	    char **tmp2 = realloc(strings, (nstr + 1) * sizeof(*strings));
942178825Sdfr	    if(tmp2 == NULL)
94355682Smarkm		goto cleanup;
944178825Sdfr	    strings = tmp2;
94555682Smarkm	    strings[nstr] = strdup(s);
94655682Smarkm	    nstr++;
94755682Smarkm	    if(strings[nstr-1] == NULL)
94855682Smarkm		goto cleanup;
949233294Sstas	    s = next_component_string(NULL, " \t", &pos);
95055682Smarkm	}
95155682Smarkm	free(tmp);
95255682Smarkm    }
95355682Smarkm    if(nstr){
95455682Smarkm	char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings));
955178825Sdfr	if(tmp == NULL)
95655682Smarkm	    goto cleanup;
95755682Smarkm	strings = tmp;
95855682Smarkm	strings[nstr] = NULL;
95955682Smarkm    }
96055682Smarkm    return strings;
96155682Smarkmcleanup:
96255682Smarkm    while(nstr--)
96355682Smarkm	free(strings[nstr]);
96455682Smarkm    free(strings);
96555682Smarkm    return NULL;
96655682Smarkm
96755682Smarkm}
96855682Smarkm
969233294Sstas/**
970233294Sstas * Get a list of configuration strings, free the result with
971233294Sstas * krb5_config_free_strings().
972233294Sstas *
973233294Sstas * @param context A Kerberos 5 context.
974233294Sstas * @param c a configuration section, or NULL to use the section from context
975233294Sstas * @param ... a list of names, terminated with NULL.
976233294Sstas *
977233294Sstas * @return TRUE or FALSE
978233294Sstas *
979233294Sstas * @ingroup krb5_support
980233294Sstas */
981233294Sstas
982233294SstasKRB5_LIB_FUNCTION char** KRB5_LIB_CALL
98355682Smarkmkrb5_config_get_strings(krb5_context context,
984102644Snectar			const krb5_config_section *c,
98555682Smarkm			...)
98655682Smarkm{
98755682Smarkm    va_list ap;
98855682Smarkm    char **ret;
98955682Smarkm    va_start(ap, c);
99055682Smarkm    ret = krb5_config_vget_strings(context, c, ap);
99155682Smarkm    va_end(ap);
99255682Smarkm    return ret;
99355682Smarkm}
99455682Smarkm
995233294Sstas/**
996233294Sstas * Free the resulting strings from krb5_config-get_strings() and
997233294Sstas * krb5_config_vget_strings().
998233294Sstas *
999233294Sstas * @param strings strings to free
1000233294Sstas *
1001233294Sstas * @ingroup krb5_support
1002233294Sstas */
1003233294Sstas
1004233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
100555682Smarkmkrb5_config_free_strings(char **strings)
100655682Smarkm{
100755682Smarkm    char **s = strings;
100855682Smarkm    while(s && *s){
100955682Smarkm	free(*s);
101055682Smarkm	s++;
101155682Smarkm    }
101255682Smarkm    free(strings);
101355682Smarkm}
101455682Smarkm
1015233294Sstas/**
1016233294Sstas * Like krb5_config_get_bool_default() but with a va_list list of
1017233294Sstas * configuration selection.
1018233294Sstas *
1019233294Sstas * Configuration value to a boolean value, where yes/true and any
1020233294Sstas * non-zero number means TRUE and other value is FALSE.
1021233294Sstas *
1022233294Sstas * @param context A Kerberos 5 context.
1023233294Sstas * @param c a configuration section, or NULL to use the section from context
1024233294Sstas * @param def_value the default value to return if no configuration
1025233294Sstas *        found in the database.
1026233294Sstas * @param args a va_list of arguments
1027233294Sstas *
1028233294Sstas * @return TRUE or FALSE
1029233294Sstas *
1030233294Sstas * @ingroup krb5_support
1031233294Sstas */
1032233294Sstas
1033233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
103455682Smarkmkrb5_config_vget_bool_default (krb5_context context,
1035102644Snectar			       const krb5_config_section *c,
103655682Smarkm			       krb5_boolean def_value,
103755682Smarkm			       va_list args)
103855682Smarkm{
103955682Smarkm    const char *str;
104055682Smarkm    str = krb5_config_vget_string (context, c, args);
104155682Smarkm    if(str == NULL)
104255682Smarkm	return def_value;
104355682Smarkm    if(strcasecmp(str, "yes") == 0 ||
104455682Smarkm       strcasecmp(str, "true") == 0 ||
104555682Smarkm       atoi(str)) return TRUE;
104655682Smarkm    return FALSE;
104755682Smarkm}
104855682Smarkm
1049233294Sstas/**
1050233294Sstas * krb5_config_get_bool() will convert the configuration
1051233294Sstas * option value to a boolean value, where yes/true and any non-zero
1052233294Sstas * number means TRUE and other value is FALSE.
1053233294Sstas *
1054233294Sstas * @param context A Kerberos 5 context.
1055233294Sstas * @param c a configuration section, or NULL to use the section from context
1056233294Sstas * @param args a va_list of arguments
1057233294Sstas *
1058233294Sstas * @return TRUE or FALSE
1059233294Sstas *
1060233294Sstas * @ingroup krb5_support
1061233294Sstas */
1062233294Sstas
1063233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
106455682Smarkmkrb5_config_vget_bool  (krb5_context context,
1065102644Snectar			const krb5_config_section *c,
106655682Smarkm			va_list args)
106755682Smarkm{
106855682Smarkm    return krb5_config_vget_bool_default (context, c, FALSE, args);
106955682Smarkm}
107055682Smarkm
1071233294Sstas/**
1072233294Sstas * krb5_config_get_bool_default() will convert the configuration
1073233294Sstas * option value to a boolean value, where yes/true and any non-zero
1074233294Sstas * number means TRUE and other value is FALSE.
1075233294Sstas *
1076233294Sstas * @param context A Kerberos 5 context.
1077233294Sstas * @param c a configuration section, or NULL to use the section from context
1078233294Sstas * @param def_value the default value to return if no configuration
1079233294Sstas *        found in the database.
1080233294Sstas * @param ... a list of names, terminated with NULL.
1081233294Sstas *
1082233294Sstas * @return TRUE or FALSE
1083233294Sstas *
1084233294Sstas * @ingroup krb5_support
1085233294Sstas */
1086233294Sstas
1087233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
108855682Smarkmkrb5_config_get_bool_default (krb5_context context,
1089102644Snectar			      const krb5_config_section *c,
109055682Smarkm			      krb5_boolean def_value,
109155682Smarkm			      ...)
109255682Smarkm{
109355682Smarkm    va_list ap;
109455682Smarkm    krb5_boolean ret;
109555682Smarkm    va_start(ap, def_value);
109655682Smarkm    ret = krb5_config_vget_bool_default(context, c, def_value, ap);
109755682Smarkm    va_end(ap);
109855682Smarkm    return ret;
109955682Smarkm}
110055682Smarkm
1101233294Sstas/**
1102233294Sstas * Like krb5_config_get_bool() but with a va_list list of
1103233294Sstas * configuration selection.
1104233294Sstas *
1105233294Sstas * Configuration value to a boolean value, where yes/true and any
1106233294Sstas * non-zero number means TRUE and other value is FALSE.
1107233294Sstas *
1108233294Sstas * @param context A Kerberos 5 context.
1109233294Sstas * @param c a configuration section, or NULL to use the section from context
1110233294Sstas * @param ... a list of names, terminated with NULL.
1111233294Sstas *
1112233294Sstas * @return TRUE or FALSE
1113233294Sstas *
1114233294Sstas * @ingroup krb5_support
1115233294Sstas */
1116233294Sstas
1117233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
111855682Smarkmkrb5_config_get_bool (krb5_context context,
1119102644Snectar		      const krb5_config_section *c,
112055682Smarkm		      ...)
112155682Smarkm{
112255682Smarkm    va_list ap;
112355682Smarkm    krb5_boolean ret;
112455682Smarkm    va_start(ap, c);
112555682Smarkm    ret = krb5_config_vget_bool (context, c, ap);
112655682Smarkm    va_end(ap);
112755682Smarkm    return ret;
112855682Smarkm}
112955682Smarkm
1130233294Sstas/**
1131233294Sstas * Get the time from the configuration file using a relative time.
1132233294Sstas *
1133233294Sstas * Like krb5_config_get_time_default() but with a va_list list of
1134233294Sstas * configuration selection.
1135233294Sstas *
1136233294Sstas * @param context A Kerberos 5 context.
1137233294Sstas * @param c a configuration section, or NULL to use the section from context
1138233294Sstas * @param def_value the default value to return if no configuration
1139233294Sstas *        found in the database.
1140233294Sstas * @param args a va_list of arguments
1141233294Sstas *
1142233294Sstas * @return parsed the time (or def_value on parse error)
1143233294Sstas *
1144233294Sstas * @ingroup krb5_support
1145233294Sstas */
1146233294Sstas
1147233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL
114855682Smarkmkrb5_config_vget_time_default (krb5_context context,
1149102644Snectar			       const krb5_config_section *c,
115055682Smarkm			       int def_value,
115155682Smarkm			       va_list args)
115255682Smarkm{
115355682Smarkm    const char *str;
1154178825Sdfr    krb5_deltat t;
1155178825Sdfr
115655682Smarkm    str = krb5_config_vget_string (context, c, args);
115755682Smarkm    if(str == NULL)
115855682Smarkm	return def_value;
1159178825Sdfr    if (krb5_string_to_deltat(str, &t))
1160178825Sdfr	return def_value;
1161178825Sdfr    return t;
116255682Smarkm}
116355682Smarkm
1164233294Sstas/**
1165233294Sstas * Get the time from the configuration file using a relative time, for example: 1h30s
1166233294Sstas *
1167233294Sstas * @param context A Kerberos 5 context.
1168233294Sstas * @param c a configuration section, or NULL to use the section from context
1169233294Sstas * @param args a va_list of arguments
1170233294Sstas *
1171233294Sstas * @return parsed the time or -1 on error
1172233294Sstas *
1173233294Sstas * @ingroup krb5_support
1174233294Sstas */
1175233294Sstas
1176233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL
117755682Smarkmkrb5_config_vget_time  (krb5_context context,
1178102644Snectar			const krb5_config_section *c,
117955682Smarkm			va_list args)
118055682Smarkm{
118155682Smarkm    return krb5_config_vget_time_default (context, c, -1, args);
118255682Smarkm}
118355682Smarkm
1184233294Sstas/**
1185233294Sstas * Get the time from the configuration file using a relative time, for example: 1h30s
1186233294Sstas *
1187233294Sstas * @param context A Kerberos 5 context.
1188233294Sstas * @param c a configuration section, or NULL to use the section from context
1189233294Sstas * @param def_value the default value to return if no configuration
1190233294Sstas *        found in the database.
1191233294Sstas * @param ... a list of names, terminated with NULL.
1192233294Sstas *
1193233294Sstas * @return parsed the time (or def_value on parse error)
1194233294Sstas *
1195233294Sstas * @ingroup krb5_support
1196233294Sstas */
1197233294Sstas
1198233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL
119955682Smarkmkrb5_config_get_time_default (krb5_context context,
1200102644Snectar			      const krb5_config_section *c,
120155682Smarkm			      int def_value,
120255682Smarkm			      ...)
120355682Smarkm{
120455682Smarkm    va_list ap;
120555682Smarkm    int ret;
120655682Smarkm    va_start(ap, def_value);
120755682Smarkm    ret = krb5_config_vget_time_default(context, c, def_value, ap);
120855682Smarkm    va_end(ap);
120955682Smarkm    return ret;
121055682Smarkm}
121155682Smarkm
1212233294Sstas/**
1213233294Sstas * Get the time from the configuration file using a relative time, for example: 1h30s
1214233294Sstas *
1215233294Sstas * @param context A Kerberos 5 context.
1216233294Sstas * @param c a configuration section, or NULL to use the section from context
1217233294Sstas * @param ... a list of names, terminated with NULL.
1218233294Sstas *
1219233294Sstas * @return parsed the time or -1 on error
1220233294Sstas *
1221233294Sstas * @ingroup krb5_support
1222233294Sstas */
1223233294Sstas
1224233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL
122555682Smarkmkrb5_config_get_time (krb5_context context,
1226102644Snectar		      const krb5_config_section *c,
122755682Smarkm		      ...)
122855682Smarkm{
122955682Smarkm    va_list ap;
123055682Smarkm    int ret;
123155682Smarkm    va_start(ap, c);
123255682Smarkm    ret = krb5_config_vget_time (context, c, ap);
123355682Smarkm    va_end(ap);
123455682Smarkm    return ret;
123555682Smarkm}
123655682Smarkm
123755682Smarkm
1238233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL
123955682Smarkmkrb5_config_vget_int_default (krb5_context context,
1240102644Snectar			      const krb5_config_section *c,
124155682Smarkm			      int def_value,
124255682Smarkm			      va_list args)
124355682Smarkm{
124455682Smarkm    const char *str;
124555682Smarkm    str = krb5_config_vget_string (context, c, args);
124655682Smarkm    if(str == NULL)
124755682Smarkm	return def_value;
1248233294Sstas    else {
1249233294Sstas	char *endptr;
1250233294Sstas	long l;
1251233294Sstas	l = strtol(str, &endptr, 0);
1252233294Sstas	if (endptr == str)
1253233294Sstas	    return def_value;
1254233294Sstas	else
125555682Smarkm	    return l;
125655682Smarkm    }
125755682Smarkm}
125855682Smarkm
1259233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL
126055682Smarkmkrb5_config_vget_int  (krb5_context context,
1261102644Snectar		       const krb5_config_section *c,
126255682Smarkm		       va_list args)
126355682Smarkm{
126455682Smarkm    return krb5_config_vget_int_default (context, c, -1, args);
126555682Smarkm}
126655682Smarkm
1267233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL
126855682Smarkmkrb5_config_get_int_default (krb5_context context,
1269102644Snectar			     const krb5_config_section *c,
127055682Smarkm			     int def_value,
127155682Smarkm			     ...)
127255682Smarkm{
127355682Smarkm    va_list ap;
127455682Smarkm    int ret;
127555682Smarkm    va_start(ap, def_value);
127655682Smarkm    ret = krb5_config_vget_int_default(context, c, def_value, ap);
127755682Smarkm    va_end(ap);
127855682Smarkm    return ret;
127955682Smarkm}
128055682Smarkm
1281233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL
128255682Smarkmkrb5_config_get_int (krb5_context context,
1283102644Snectar		     const krb5_config_section *c,
128455682Smarkm		     ...)
128555682Smarkm{
128655682Smarkm    va_list ap;
128755682Smarkm    int ret;
128855682Smarkm    va_start(ap, c);
128955682Smarkm    ret = krb5_config_vget_int (context, c, ap);
129055682Smarkm    va_end(ap);
129155682Smarkm    return ret;
129255682Smarkm}
1293233294Sstas
1294233294Sstas
1295233294Sstas#ifndef HEIMDAL_SMALLER
1296233294Sstas
1297233294Sstas/**
1298233294Sstas * Deprecated: configuration files are not strings
1299233294Sstas *
1300233294Sstas * @ingroup krb5_deprecated
1301233294Sstas */
1302233294Sstas
1303233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1304233294Sstaskrb5_config_parse_string_multi(krb5_context context,
1305233294Sstas			       const char *string,
1306233294Sstas			       krb5_config_section **res)
1307233294Sstas    KRB5_DEPRECATED_FUNCTION("Use X instead")
1308233294Sstas{
1309233294Sstas    const char *str;
1310233294Sstas    unsigned lineno = 0;
1311233294Sstas    krb5_error_code ret;
1312233294Sstas    struct fileptr f;
1313233294Sstas    f.f = NULL;
1314233294Sstas    f.s = string;
1315233294Sstas
1316233294Sstas    ret = krb5_config_parse_debug (&f, res, &lineno, &str);
1317233294Sstas    if (ret) {
1318233294Sstas	krb5_set_error_message (context, ret, "%s:%u: %s",
1319233294Sstas				"<constant>", lineno, str);
1320233294Sstas	return ret;
1321233294Sstas    }
1322233294Sstas    return 0;
1323233294Sstas}
1324233294Sstas
1325233294Sstas#endif
1326