Line data Source code
1 : /*
2 : * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : *
12 : * 1. Redistributions of source code must retain the above copyright
13 : * notice, this list of conditions and the following disclaimer.
14 : *
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.
18 : *
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.
22 : *
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.
34 : */
35 :
36 : #include "baselocl.h"
37 : #include <assert.h>
38 : #include <ctype.h>
39 : #include <parse_time.h>
40 :
41 : #if defined(HAVE_FRAMEWORK_COREFOUNDATION)
42 : #include <CoreFoundation/CoreFoundation.h>
43 : #endif
44 :
45 : /* Gaah! I want a portable funopen */
46 : struct fileptr {
47 : heim_context context;
48 : const char *s;
49 : FILE *f;
50 : };
51 :
52 : static char *
53 57267055 : config_fgets(char *str, size_t len, struct fileptr *ptr)
54 : {
55 : /* XXX this is not correct, in that they don't do the same if the
56 : line is longer than len */
57 57267055 : if(ptr->f != NULL)
58 57267055 : return fgets(str, len, ptr->f);
59 : else {
60 : /* this is almost strsep_copy */
61 : const char *p;
62 : ssize_t l;
63 0 : if(*ptr->s == '\0')
64 0 : return NULL;
65 0 : p = ptr->s + strcspn(ptr->s, "\n");
66 0 : if(*p == '\n')
67 0 : p++;
68 0 : l = min(len, (size_t)(p - ptr->s));
69 0 : if(len > 0) {
70 0 : memcpy(str, ptr->s, l);
71 0 : str[l] = '\0';
72 : }
73 0 : ptr->s = p;
74 0 : return str;
75 : }
76 : }
77 :
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);
88 :
89 : heim_config_section *
90 36705666 : heim_config_get_entry(heim_config_section **parent, const char *name, int type)
91 : {
92 : heim_config_section **q;
93 :
94 108012158 : for (q = parent; *q != NULL; q = &(*q)->next)
95 85491419 : if (type == heim_config_list &&
96 28367902 : (unsigned)type == (*q)->type &&
97 14183951 : strcmp(name, (*q)->name) == 0)
98 976 : return *q;
99 36704690 : *q = calloc(1, sizeof(**q));
100 36704690 : if (*q == NULL)
101 0 : return NULL;
102 36704690 : (*q)->name = strdup(name);
103 36704690 : (*q)->type = type;
104 36704690 : if ((*q)->name == NULL) {
105 0 : free(*q);
106 0 : *q = NULL;
107 0 : return NULL;
108 : }
109 36704690 : return *q;
110 : }
111 :
112 : /*
113 : * Parse a section:
114 : *
115 : * [section]
116 : * foo = bar
117 : * b = {
118 : * a
119 : * }
120 : * ...
121 : *
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'.
125 : */
126 :
127 : static heim_error_code
128 3739920 : parse_section(char *p, heim_config_section **s, heim_config_section **parent,
129 : const char **err_message)
130 : {
131 : char *p1;
132 : heim_config_section *tmp;
133 :
134 3739920 : p1 = strchr (p + 1, ']');
135 3739920 : if (p1 == NULL) {
136 0 : *err_message = "missing ]";
137 0 : return HEIM_ERR_CONFIG_BADFORMAT;
138 : }
139 3739920 : *p1 = '\0';
140 3739920 : tmp = heim_config_get_entry(parent, p + 1, heim_config_list);
141 3739920 : if(tmp == NULL) {
142 0 : *err_message = "out of memory";
143 0 : return HEIM_ERR_CONFIG_BADFORMAT;
144 : }
145 3739920 : *s = tmp;
146 3739920 : return 0;
147 : }
148 :
149 : /*
150 : * Parse a brace-enclosed list from `f', hooking in the structure at
151 : * `parent'.
152 : * Store the error message in `err_message'.
153 : */
154 :
155 : static heim_error_code
156 4301768 : parse_list(struct fileptr *f, unsigned *lineno, heim_config_binding **parent,
157 : const char **err_message)
158 : {
159 : char buf[2048];
160 : heim_error_code ret;
161 4301768 : heim_config_binding *b = NULL;
162 4301768 : unsigned beg_lineno = *lineno;
163 :
164 25806712 : while(config_fgets(buf, sizeof(buf), f) != NULL) {
165 : char *p;
166 :
167 21504944 : ++*lineno;
168 21504944 : buf[strcspn(buf, "\r\n")] = '\0';
169 21504944 : p = buf;
170 81729180 : while(isspace((unsigned char)*p))
171 38719292 : ++p;
172 21504944 : if (*p == '#' || *p == ';' || *p == '\0')
173 0 : continue;
174 43009888 : while(isspace((unsigned char)*p))
175 0 : ++p;
176 21504944 : if (*p == '}')
177 4301768 : return 0;
178 17203176 : if (*p == '\0')
179 0 : continue;
180 17203176 : ret = parse_binding (f, lineno, p, &b, parent, err_message);
181 17203176 : if (ret)
182 0 : return ret;
183 : }
184 0 : *lineno = beg_lineno;
185 0 : *err_message = "unclosed {";
186 0 : return HEIM_ERR_CONFIG_BADFORMAT;
187 : }
188 :
189 : /*
190 : *
191 : */
192 :
193 : static heim_error_code
194 32965746 : parse_binding(struct fileptr *f, unsigned *lineno, char *p,
195 : heim_config_binding **b, heim_config_binding **parent,
196 : const char **err_message)
197 : {
198 : heim_config_binding *tmp;
199 : char *p1, *p2;
200 32965746 : heim_error_code ret = 0;
201 :
202 32965746 : p1 = p;
203 562436762 : while (*p && *p != '=' && !isspace((unsigned char)*p))
204 496505270 : ++p;
205 32965746 : if (*p == '\0') {
206 0 : *err_message = "missing =";
207 0 : return HEIM_ERR_CONFIG_BADFORMAT;
208 : }
209 32965746 : p2 = p;
210 98897238 : while (isspace((unsigned char)*p))
211 32965746 : ++p;
212 32965746 : if (*p != '=') {
213 0 : *err_message = "missing =";
214 0 : return HEIM_ERR_CONFIG_BADFORMAT;
215 : }
216 32965746 : ++p;
217 98897238 : while(isspace((unsigned char)*p))
218 32965746 : ++p;
219 32965746 : *p2 = '\0';
220 32965746 : if (*p == '{') {
221 4301768 : tmp = heim_config_get_entry(parent, p1, heim_config_list);
222 4301768 : if (tmp == NULL) {
223 0 : *err_message = "out of memory";
224 0 : return HEIM_ERR_CONFIG_BADFORMAT;
225 : }
226 4301768 : ret = parse_list (f, lineno, &tmp->u.list, err_message);
227 : } else {
228 28663978 : tmp = heim_config_get_entry(parent, p1, heim_config_string);
229 28663978 : if (tmp == NULL) {
230 0 : *err_message = "out of memory";
231 0 : return HEIM_ERR_CONFIG_BADFORMAT;
232 : }
233 28663978 : p1 = p;
234 28663978 : p = p1 + strlen(p1);
235 57327956 : while(p > p1 && isspace((unsigned char)*(p-1)))
236 0 : --p;
237 28663978 : *p = '\0';
238 28663978 : tmp->u.string = strdup(p1);
239 : }
240 32965746 : *b = tmp;
241 32965746 : return ret;
242 : }
243 :
244 : #if defined(HAVE_FRAMEWORK_COREFOUNDATION)
245 :
246 : #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
247 : #define HAVE_CFPROPERTYLISTCREATEWITHSTREAM 1
248 : #endif
249 :
250 : static char *
251 : cfstring2cstring(CFStringRef string)
252 : {
253 : CFIndex len;
254 : char *str;
255 :
256 : str = (char *) CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
257 : if (str)
258 : return strdup(str);
259 :
260 : len = CFStringGetLength(string);
261 : len = 1 + CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8);
262 : str = malloc(len);
263 : if (str == NULL)
264 : return NULL;
265 :
266 : if (!CFStringGetCString (string, str, len, kCFStringEncodingUTF8)) {
267 : free (str);
268 : return NULL;
269 : }
270 : return str;
271 : }
272 :
273 : static void
274 : convert_content(const void *key, const void *value, void *context)
275 : {
276 : heim_config_section *tmp, **parent = context;
277 : char *k;
278 :
279 : if (CFGetTypeID(key) != CFStringGetTypeID())
280 : return;
281 :
282 : k = cfstring2cstring(key);
283 : if (k == NULL)
284 : return;
285 :
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 */
294 : }
295 : free(k);
296 : }
297 :
298 : static heim_error_code
299 : parse_plist_config(heim_context context, const char *path, heim_config_section **parent)
300 : {
301 : CFReadStreamRef s;
302 : CFDictionaryRef d;
303 : CFURLRef url;
304 :
305 : url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)path, strlen(path), 0);
306 : if (url == NULL) {
307 : heim_clear_error_message(context);
308 : return ENOMEM;
309 : }
310 :
311 : s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
312 : CFRelease(url);
313 : if (s == NULL) {
314 : heim_clear_error_message(context);
315 : return ENOMEM;
316 : }
317 :
318 : if (!CFReadStreamOpen(s)) {
319 : CFRelease(s);
320 : heim_clear_error_message(context);
321 : return ENOENT;
322 : }
323 :
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;
333 : }
334 :
335 : CFDictionaryApplyFunction(d, convert_content, parent);
336 : CFRelease(d);
337 :
338 : return 0;
339 : }
340 :
341 : #endif
342 :
343 : static int
344 0 : is_absolute_path(const char *path)
345 : {
346 : /*
347 : * An absolute path is one that refers to an explicit object
348 : * without ambiguity.
349 : */
350 : #ifdef WIN32
351 : size_t len = strlen(path);
352 :
353 : /* UNC path is by definition absolute */
354 : if (len > 2
355 : && ISPATHSEP(path[0])
356 : && ISPATHSEP(path[1]))
357 : return 1;
358 :
359 : /* A drive letter path might be absolute */
360 : if (len > 3
361 : && isalpha(path[0])
362 : && path[1] == ':'
363 : && ISPATHSEP(path[2]))
364 : return 1;
365 :
366 : /*
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.
370 : */
371 : #else
372 : /* UNIX is easy, first char '/' is absolute */
373 0 : if (ISPATHSEP(path[0]))
374 0 : return 1;
375 : #endif
376 0 : return 0;
377 : }
378 :
379 : /*
380 : * Parse the config file `fname', generating the structures into `res'
381 : * returning error messages in `err_message'
382 : */
383 :
384 : static heim_error_code
385 941541 : heim_config_parse_debug(struct fileptr *f,
386 : heim_config_section **res,
387 : unsigned *lineno,
388 : const char **err_message)
389 : {
390 941541 : heim_config_section *s = NULL;
391 941541 : heim_config_binding *b = NULL;
392 : char buf[2048];
393 : heim_error_code ret;
394 :
395 941541 : *lineno = 0;
396 941541 : *err_message = "";
397 :
398 36703652 : while (config_fgets(buf, sizeof(buf), f) != NULL) {
399 : char *p;
400 :
401 34820570 : ++*lineno;
402 34820570 : buf[strcspn(buf, "\r\n")] = '\0';
403 34820570 : p = buf;
404 88362668 : while(isspace((unsigned char)*p))
405 18721528 : ++p;
406 34820570 : if (*p == '#' || *p == ';')
407 2823699 : continue;
408 31996871 : if (*p == '[') {
409 3739920 : ret = parse_section(p, &s, res, err_message);
410 3739920 : if (ret)
411 0 : return ret;
412 3739920 : b = NULL;
413 28256951 : } else if (*p == '}') {
414 0 : *err_message = "unmatched }";
415 0 : return 2048;
416 28256951 : } else if (strncmp(p, "include", sizeof("include") - 1) == 0 &&
417 0 : isspace(p[sizeof("include") - 1])) {
418 0 : p += sizeof("include");
419 0 : while (isspace(*p))
420 0 : p++;
421 0 : if (!is_absolute_path(p)) {
422 0 : heim_set_error_message(f->context, HEIM_ERR_CONFIG_BADFORMAT,
423 : "Configuration include path must be "
424 : "absolute");
425 0 : return HEIM_ERR_CONFIG_BADFORMAT;
426 : }
427 0 : ret = heim_config_parse_file_multi(f->context, p, res);
428 0 : if (ret)
429 0 : return ret;
430 28256951 : } else if (strncmp(p, "includedir", sizeof("includedir") - 1) == 0 &&
431 0 : isspace(p[sizeof("includedir") - 1])) {
432 0 : p += sizeof("includedir");
433 0 : while (isspace(*p))
434 0 : p++;
435 0 : if (!is_absolute_path(p)) {
436 0 : heim_set_error_message(f->context, HEIM_ERR_CONFIG_BADFORMAT,
437 : "Configuration includedir path must be "
438 : "absolute");
439 0 : return HEIM_ERR_CONFIG_BADFORMAT;
440 : }
441 0 : ret = heim_config_parse_dir_multi(f->context, p, res);
442 0 : if (ret)
443 0 : return ret;
444 28256951 : } else if(*p != '\0') {
445 15762570 : if (s == NULL) {
446 0 : *err_message = "binding before section";
447 0 : return 2048;
448 : }
449 15762570 : ret = parse_binding(f, lineno, p, &b, &s->u.list, err_message);
450 15762570 : if (ret)
451 0 : return ret;
452 : }
453 : }
454 941541 : return 0;
455 : }
456 :
457 : static int
458 2076982 : is_plist_file(const char *fname)
459 : {
460 2076982 : size_t len = strlen(fname);
461 2076982 : char suffix[] = ".plist";
462 2076982 : if (len < sizeof(suffix))
463 0 : return 0;
464 2076982 : if (strcasecmp(&fname[len - (sizeof(suffix) - 1)], suffix) != 0)
465 2076982 : return 0;
466 0 : return 1;
467 : }
468 :
469 : /**
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.
474 : *
475 : * This interface can be used to parse several configuration directories
476 : * into one resulting heim_config_section by calling it repeatably.
477 : *
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().
482 : *
483 : * @ingroup heim_support
484 : */
485 :
486 : heim_error_code
487 0 : heim_config_parse_dir_multi(heim_context context,
488 : const char *dname,
489 : heim_config_section **res)
490 : {
491 : struct dirent *entry;
492 : heim_error_code ret;
493 : DIR *d;
494 :
495 0 : if ((d = opendir(dname)) == NULL)
496 0 : return errno;
497 :
498 0 : while ((entry = readdir(d)) != NULL) {
499 0 : char *p = entry->d_name;
500 : char *path;
501 0 : int is_valid = 1;
502 :
503 0 : while (*p) {
504 : /*
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.
510 : */
511 0 : if (!isalnum(*p) && *p != '_' && *p != '-' &&
512 0 : strcmp(p, ".conf") != 0) {
513 0 : is_valid = 0;
514 0 : break;
515 : }
516 0 : p++;
517 : }
518 0 : if (!is_valid)
519 0 : continue;
520 :
521 0 : if (asprintf(&path, "%s/%s", dname, entry->d_name) == -1 ||
522 0 : path == NULL) {
523 0 : (void) closedir(d);
524 0 : return heim_enomem(context);
525 : }
526 0 : ret = heim_config_parse_file_multi(context, path, res);
527 0 : free(path);
528 0 : if (ret == ENOMEM) {
529 0 : (void) closedir(d);
530 0 : return ENOMEM;
531 : }
532 : /* Ignore malformed config files so we don't lock out admins, etc... */
533 : }
534 0 : (void) closedir(d);
535 0 : return 0;
536 : }
537 :
538 : /**
539 : * Parse a configuration file and add the result into res. This
540 : * interface can be used to parse several configuration files into one
541 : * resulting heim_config_section by calling it repeatably.
542 : *
543 : * @param context a Kerberos 5 context.
544 : * @param fname a file name to a Kerberos configuration file
545 : * @param res the returned result, must be free with heim_free_config_files().
546 : * @return Return an error code or 0, see heim_get_error_message().
547 : *
548 : * @ingroup heim_support
549 : */
550 :
551 : HEIMDAL_THREAD_LOCAL int config_include_depth = 0;
552 :
553 : heim_error_code
554 2076982 : heim_config_parse_file_multi(heim_context context,
555 : const char *fname,
556 : heim_config_section **res)
557 : {
558 : const char *str;
559 2076982 : char *newfname = NULL;
560 2076982 : unsigned lineno = 0;
561 2076982 : heim_error_code ret = 0;
562 : struct fileptr f;
563 : struct stat st;
564 :
565 2076982 : if (config_include_depth > 5) {
566 0 : heim_warnx(context, "Maximum config file include depth reached; "
567 : "not including %s", fname);
568 0 : return 0;
569 : }
570 2076982 : config_include_depth++;
571 :
572 : /**
573 : * If the fname starts with "~/" parse configuration file in the
574 : * current users home directory. The behavior can be disabled and
575 : * enabled by calling heim_set_home_dir_access().
576 : */
577 2076982 : if (ISTILDE(fname[0]) && ISPATHSEP(fname[1])) {
578 555900 : if (!heim_context_get_homedir_access(context)) {
579 0 : heim_set_error_message(context, EPERM,
580 : "Access to home directory not allowed");
581 0 : ret = EPERM;
582 0 : goto out;
583 : }
584 1111800 : if (asprintf(&newfname, "%%{USERCONFIG}%s", &fname[1]) < 0 ||
585 555900 : newfname == NULL) {
586 0 : ret = heim_enomem(context);
587 0 : goto out;
588 : }
589 555900 : fname = newfname;
590 : }
591 :
592 2076982 : if (is_plist_file(fname)) {
593 : #if defined(HAVE_FRAMEWORK_COREFOUNDATION)
594 : ret = parse_plist_config(context, fname, res);
595 : if (ret) {
596 : heim_set_error_message(context, ret,
597 : "Failed to parse plist %s", fname);
598 : goto out;
599 : }
600 : #else
601 0 : heim_set_error_message(context, ENOENT,
602 : "no support for plist configuration files");
603 0 : ret = ENOENT;
604 0 : goto out;
605 : #endif
606 : } else {
607 2076982 : char *exp_fname = NULL;
608 :
609 : /*
610 : * Note that heim_config_parse_dir_multi() doesn't want tokens
611 : * expanded here, but it happens to limit the names of files to
612 : * include such that there can be no tokens to expand. Don't
613 : * add token expansion for tokens using _, say.
614 : */
615 2076982 : ret = heim_expand_path_tokens(context, fname, 1, &exp_fname, NULL);
616 2076982 : if (ret)
617 1135441 : goto out;
618 2076982 : free(newfname);
619 2076982 : fname = newfname = exp_fname;
620 :
621 2076982 : f.context = context;
622 2076982 : f.f = fopen(fname, "r");
623 2076982 : f.s = NULL;
624 2076982 : if (f.f == NULL || fstat(fileno(f.f), &st) == -1) {
625 1135441 : if (f.f != NULL)
626 0 : (void) fclose(f.f);
627 1135441 : ret = errno;
628 1135441 : heim_set_error_message(context, ret, "open or stat %s: %s",
629 : fname, strerror(ret));
630 1135441 : goto out;
631 : }
632 :
633 941541 : if (!S_ISREG(st.st_mode)) {
634 0 : (void) fclose(f.f);
635 0 : heim_set_error_message(context, EISDIR, "not a regular file %s: %s",
636 : fname, strerror(EISDIR));
637 0 : ret = EISDIR;
638 0 : goto out;
639 : }
640 :
641 941541 : ret = heim_config_parse_debug(&f, res, &lineno, &str);
642 941541 : fclose(f.f);
643 941541 : if (ret) {
644 0 : if (ret != HEIM_ERR_CONFIG_BADFORMAT)
645 0 : ret = HEIM_ERR_CONFIG_BADFORMAT;
646 0 : heim_set_error_message(context, ret, "%s:%u: %s",
647 : fname, lineno, str);
648 0 : goto out;
649 : }
650 : }
651 :
652 2076982 : out:
653 2076982 : config_include_depth--;
654 2076982 : if (ret == HEIM_ERR_CONFIG_BADFORMAT || (ret && config_include_depth > 0)) {
655 0 : heim_warn(context, ret, "Ignoring");
656 0 : if (config_include_depth > 0)
657 0 : ret = 0;
658 : }
659 2076982 : free(newfname);
660 2076982 : return ret;
661 : }
662 :
663 : heim_error_code
664 0 : heim_config_parse_file(heim_context context,
665 : const char *fname,
666 : heim_config_section **res)
667 : {
668 0 : *res = NULL;
669 0 : return heim_config_parse_file_multi(context, fname, res);
670 : }
671 :
672 : static void
673 9852648 : free_binding(heim_context context, heim_config_binding *b)
674 : {
675 : heim_config_binding *next_b;
676 :
677 55487526 : while (b) {
678 35782230 : free (b->name);
679 35782230 : assert(b->type == heim_config_string || b->type == heim_config_list);
680 35782230 : if (b->type == heim_config_string)
681 27940032 : free (b->u.string);
682 : else
683 7842198 : free_binding (context, b->u.list);
684 35782230 : next_b = b->next;
685 35782230 : free (b);
686 35782230 : b = next_b;
687 : }
688 9852648 : }
689 :
690 : /**
691 : * Free configuration file section, the result of
692 : * heim_config_parse_file() and heim_config_parse_file_multi().
693 : *
694 : * @param context A Kerberos 5 context
695 : * @param s the configuration section to free
696 : *
697 : * @return returns 0 on successes, otherwise an error code, see
698 : * heim_get_error_message()
699 : *
700 : * @ingroup heim_support
701 : */
702 :
703 : heim_error_code
704 2010450 : heim_config_file_free(heim_context context, heim_config_section *s)
705 : {
706 2010450 : free_binding (context, s);
707 2010450 : return 0;
708 : }
709 :
710 : #ifndef HEIMDAL_SMALLER
711 :
712 : heim_error_code
713 0 : heim_config_copy(heim_context context,
714 : heim_config_section *c,
715 : heim_config_section **head)
716 : {
717 0 : heim_config_binding *d, *previous = NULL;
718 :
719 0 : *head = NULL;
720 :
721 0 : while (c) {
722 0 : d = calloc(1, sizeof(*d));
723 :
724 0 : if (*head == NULL)
725 0 : *head = d;
726 :
727 0 : d->name = strdup(c->name);
728 0 : d->type = c->type;
729 0 : assert(d->type == heim_config_string || d->type == heim_config_list);
730 0 : if (d->type == heim_config_string)
731 0 : d->u.string = strdup(c->u.string);
732 : else
733 0 : heim_config_copy (context, c->u.list, &d->u.list);
734 0 : if (previous)
735 0 : previous->next = d;
736 :
737 0 : previous = d;
738 0 : c = c->next;
739 : }
740 0 : return 0;
741 : }
742 :
743 : #endif /* HEIMDAL_SMALLER */
744 :
745 : const void *
746 0 : heim_config_get_next(heim_context context,
747 : const heim_config_section *c,
748 : const heim_config_binding **pointer,
749 : int type,
750 : ...)
751 : {
752 : const char *ret;
753 : va_list args;
754 :
755 0 : va_start(args, type);
756 0 : ret = heim_config_vget_next(context, c, pointer, type, args);
757 0 : va_end(args);
758 0 : return ret;
759 : }
760 :
761 : static const void *
762 61030429 : vget_next(heim_context context,
763 : const heim_config_binding *b,
764 : const heim_config_binding **pointer,
765 : int type,
766 : const char *name,
767 : va_list args)
768 : {
769 61030429 : const char *p = va_arg(args, const char *);
770 :
771 361411469 : while (b != NULL) {
772 271458105 : if (strcmp(b->name, name) == 0) {
773 32128338 : if (b->type == (unsigned)type && p == NULL) {
774 2126298 : *pointer = b;
775 2126298 : return b->u.generic;
776 30002040 : } else if (b->type == heim_config_list && p != NULL) {
777 29981196 : return vget_next(context, b->u.list, pointer, type, p, args);
778 : }
779 : }
780 239350611 : b = b->next;
781 : }
782 28922935 : return NULL;
783 : }
784 :
785 : const void *
786 32412393 : heim_config_vget_next(heim_context context,
787 : const heim_config_section *c,
788 : const heim_config_binding **pointer,
789 : int type,
790 : va_list args)
791 : {
792 : const heim_config_binding *b;
793 : const char *p;
794 :
795 32412393 : if (c == NULL)
796 1169033 : return NULL;
797 :
798 31243360 : if (*pointer == NULL) {
799 : /* first time here, walk down the tree looking for the right
800 : section */
801 31049233 : p = va_arg(args, const char *);
802 31049233 : if (p == NULL)
803 0 : return NULL;
804 31049233 : return vget_next(context, c, pointer, type, p, args);
805 : }
806 :
807 : /* we were called again, so just look for more entries with the
808 : same name and type */
809 749777 : for (b = (*pointer)->next; b != NULL; b = b->next) {
810 555853 : if(strcmp(b->name, (*pointer)->name) == 0 && b->type == (unsigned)type) {
811 203 : *pointer = b;
812 203 : return b->u.generic;
813 : }
814 : }
815 193924 : return NULL;
816 : }
817 :
818 : const void *
819 0 : heim_config_get(heim_context context,
820 : const heim_config_section *c,
821 : int type,
822 : ...)
823 : {
824 : const void *ret;
825 : va_list args;
826 :
827 0 : va_start(args, type);
828 0 : ret = heim_config_vget(context, c, type, args);
829 0 : va_end(args);
830 0 : return ret;
831 : }
832 :
833 :
834 : const void *
835 24361649 : heim_config_vget(heim_context context,
836 : const heim_config_section *c,
837 : int type,
838 : va_list args)
839 : {
840 24361649 : const heim_config_binding *foo = NULL;
841 :
842 24361649 : return heim_config_vget_next(context, c, &foo, type, args);
843 : }
844 :
845 : /**
846 : * Get a list of configuration binding list for more processing
847 : *
848 : * @param context A Kerberos 5 context.
849 : * @param c a configuration section, or NULL to use the section from context
850 : * @param ... a list of names, terminated with NULL.
851 : *
852 : * @return NULL if configuration list is not found, a list otherwise
853 : *
854 : * @ingroup heim_support
855 : */
856 :
857 : const heim_config_binding *
858 0 : heim_config_get_list(heim_context context,
859 : const heim_config_section *c,
860 : ...)
861 : {
862 : const heim_config_binding *ret;
863 : va_list args;
864 :
865 0 : va_start(args, c);
866 0 : ret = heim_config_vget_list(context, c, args);
867 0 : va_end(args);
868 0 : return ret;
869 : }
870 :
871 : /**
872 : * Get a list of configuration binding list for more processing
873 : *
874 : * @param context A Kerberos 5 context.
875 : * @param c a configuration section, or NULL to use the section from context
876 : * @param args a va_list of arguments
877 : *
878 : * @return NULL if configuration list is not found, a list otherwise
879 : *
880 : * @ingroup heim_support
881 : */
882 :
883 : const heim_config_binding *
884 0 : heim_config_vget_list(heim_context context,
885 : const heim_config_section *c,
886 : va_list args)
887 : {
888 0 : return heim_config_vget(context, c, heim_config_list, args);
889 : }
890 :
891 : /**
892 : * Returns a "const char *" to a string in the configuration database.
893 : * The string may not be valid after a reload of the configuration
894 : * database so a caller should make a local copy if it needs to keep
895 : * the string.
896 : *
897 : * @param context A Kerberos 5 context.
898 : * @param c a configuration section, or NULL to use the section from context
899 : * @param ... a list of names, terminated with NULL.
900 : *
901 : * @return NULL if configuration string not found, a string otherwise
902 : *
903 : * @ingroup heim_support
904 : */
905 :
906 : const char *
907 555816 : heim_config_get_string(heim_context context,
908 : const heim_config_section *c,
909 : ...)
910 : {
911 : const char *ret;
912 : va_list args;
913 :
914 555816 : va_start(args, c);
915 555816 : ret = heim_config_vget_string(context, c, args);
916 555816 : va_end(args);
917 555816 : return ret;
918 : }
919 :
920 : /**
921 : * Like heim_config_get_string(), but uses a va_list instead of ...
922 : *
923 : * @param context A Kerberos 5 context.
924 : * @param c a configuration section, or NULL to use the section from context
925 : * @param args a va_list of arguments
926 : *
927 : * @return NULL if configuration string not found, a string otherwise
928 : *
929 : * @ingroup heim_support
930 : */
931 :
932 : const char *
933 24361649 : heim_config_vget_string(heim_context context,
934 : const heim_config_section *c,
935 : va_list args)
936 : {
937 24361649 : return heim_config_vget(context, c, heim_config_string, args);
938 : }
939 :
940 : /**
941 : * Like heim_config_vget_string(), but instead of returning NULL,
942 : * instead return a default value.
943 : *
944 : * @param context A Kerberos 5 context.
945 : * @param c a configuration section, or NULL to use the section from context
946 : * @param def_value the default value to return if no configuration
947 : * found in the database.
948 : * @param args a va_list of arguments
949 : *
950 : * @return a configuration string
951 : *
952 : * @ingroup heim_support
953 : */
954 :
955 : const char *
956 4759700 : heim_config_vget_string_default(heim_context context,
957 : const heim_config_section *c,
958 : const char *def_value,
959 : va_list args)
960 : {
961 : const char *ret;
962 :
963 4759700 : ret = heim_config_vget_string(context, c, args);
964 4759700 : if (ret == NULL)
965 4752552 : ret = def_value;
966 4759700 : return ret;
967 : }
968 :
969 : /**
970 : * Like heim_config_get_string(), but instead of returning NULL,
971 : * instead return a default value.
972 : *
973 : * @param context A Kerberos 5 context.
974 : * @param c a configuration section, or NULL to use the section from context
975 : * @param def_value the default value to return if no configuration
976 : * found in the database.
977 : * @param ... a list of names, terminated with NULL.
978 : *
979 : * @return a configuration string
980 : *
981 : * @ingroup heim_support
982 : */
983 :
984 : const char *
985 0 : heim_config_get_string_default(heim_context context,
986 : const heim_config_section *c,
987 : const char *def_value,
988 : ...)
989 : {
990 : const char *ret;
991 : va_list args;
992 :
993 0 : va_start(args, def_value);
994 0 : ret = heim_config_vget_string_default (context, c, def_value, args);
995 0 : va_end(args);
996 0 : return ret;
997 : }
998 :
999 : static char *
1000 649394 : next_component_string(char * begin, const char * delims, char **state)
1001 : {
1002 : char * end;
1003 :
1004 649394 : if (begin == NULL)
1005 455267 : begin = *state;
1006 :
1007 649394 : if (*begin == '\0')
1008 194127 : return NULL;
1009 :
1010 455267 : end = begin;
1011 910534 : while (*end == '"') {
1012 0 : char * t = strchr(end + 1, '"');
1013 :
1014 0 : if (t)
1015 0 : end = ++t;
1016 : else
1017 0 : end += strlen(end);
1018 : }
1019 :
1020 455267 : if (*end != '\0') {
1021 : size_t pos;
1022 :
1023 455267 : pos = strcspn(end, delims);
1024 455267 : end = end + pos;
1025 : }
1026 :
1027 455267 : if (*end != '\0') {
1028 261140 : *end = '\0';
1029 261140 : *state = end + 1;
1030 261140 : if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) {
1031 0 : begin++; *(end - 1) = '\0';
1032 : }
1033 261140 : return begin;
1034 : }
1035 :
1036 194127 : *state = end;
1037 194127 : if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) {
1038 0 : begin++; *(end - 1) = '\0';
1039 : }
1040 194127 : return begin;
1041 : }
1042 :
1043 : /**
1044 : * Get a list of configuration strings, free the result with
1045 : * heim_config_free_strings().
1046 : *
1047 : * @param context A Kerberos 5 context.
1048 : * @param c a configuration section, or NULL to use the section from context
1049 : * @param args a va_list of arguments
1050 : *
1051 : * @return TRUE or FALSE
1052 : *
1053 : * @ingroup heim_support
1054 : */
1055 :
1056 : char **
1057 7856617 : heim_config_vget_strings(heim_context context,
1058 : const heim_config_section *c,
1059 : va_list args)
1060 : {
1061 7856617 : char **strings = NULL;
1062 7856617 : size_t nstr = 0;
1063 7856617 : const heim_config_binding *b = NULL;
1064 : const char *p;
1065 :
1066 15907361 : while((p = heim_config_vget_next(context, c, &b,
1067 : heim_config_string, args))) {
1068 194127 : char *tmp = strdup(p);
1069 194127 : char *pos = NULL;
1070 : char *s;
1071 194127 : if(tmp == NULL)
1072 0 : goto cleanup;
1073 194127 : s = next_component_string(tmp, " \t", &pos);
1074 843521 : while(s){
1075 455267 : char **tmp2 = realloc(strings, (nstr + 1) * sizeof(*strings));
1076 455267 : if(tmp2 == NULL) {
1077 0 : free(tmp);
1078 0 : goto cleanup;
1079 : }
1080 455267 : strings = tmp2;
1081 455267 : strings[nstr] = strdup(s);
1082 455267 : nstr++;
1083 455267 : if(strings[nstr-1] == NULL) {
1084 0 : free(tmp);
1085 0 : goto cleanup;
1086 : }
1087 455267 : s = next_component_string(NULL, " \t", &pos);
1088 : }
1089 194127 : free(tmp);
1090 : }
1091 7856617 : if(nstr){
1092 193924 : char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings));
1093 193924 : if(tmp == NULL)
1094 0 : goto cleanup;
1095 193924 : strings = tmp;
1096 193924 : strings[nstr] = NULL;
1097 : }
1098 7856617 : return strings;
1099 0 : cleanup:
1100 0 : while(nstr--)
1101 0 : free(strings[nstr]);
1102 0 : free(strings);
1103 0 : return NULL;
1104 :
1105 : }
1106 :
1107 : /**
1108 : * Get a list of configuration strings, free the result with
1109 : * heim_config_free_strings().
1110 : *
1111 : * @param context A Kerberos 5 context.
1112 : * @param c a configuration section, or NULL to use the section from context
1113 : * @param ... a list of names, terminated with NULL.
1114 : *
1115 : * @return TRUE or FALSE
1116 : *
1117 : * @ingroup heim_support
1118 : */
1119 :
1120 : char **
1121 0 : heim_config_get_strings(heim_context context,
1122 : const heim_config_section *c,
1123 : ...)
1124 : {
1125 : va_list ap;
1126 : char **ret;
1127 0 : va_start(ap, c);
1128 0 : ret = heim_config_vget_strings(context, c, ap);
1129 0 : va_end(ap);
1130 0 : return ret;
1131 : }
1132 :
1133 : /**
1134 : * Free the resulting strings from heim_config-get_strings() and
1135 : * heim_config_vget_strings().
1136 : *
1137 : * @param strings strings to free
1138 : *
1139 : * @ingroup heim_support
1140 : */
1141 :
1142 : void
1143 2066458 : heim_config_free_strings(char **strings)
1144 : {
1145 2066458 : char **s = strings;
1146 :
1147 4573944 : while (s && *s) {
1148 441028 : free(*s);
1149 441028 : s++;
1150 : }
1151 2066458 : free(strings);
1152 2066458 : }
1153 :
1154 : /**
1155 : * Like heim_config_get_bool_default() but with a va_list list of
1156 : * configuration selection.
1157 : *
1158 : * Configuration value to a boolean value, where yes/true and any
1159 : * non-zero number means TRUE and other value is FALSE.
1160 : *
1161 : * @param context A Kerberos 5 context.
1162 : * @param c a configuration section, or NULL to use the section from context
1163 : * @param def_value the default value to return if no configuration
1164 : * found in the database.
1165 : * @param args a va_list of arguments
1166 : *
1167 : * @return TRUE or FALSE
1168 : *
1169 : * @ingroup heim_support
1170 : */
1171 :
1172 : int
1173 9982040 : heim_config_vget_bool_default(heim_context context,
1174 : const heim_config_section *c,
1175 : int def_value,
1176 : va_list args)
1177 : {
1178 : const char *str;
1179 9982040 : str = heim_config_vget_string(context, c, args);
1180 9982040 : if (str == NULL)
1181 8056956 : return def_value;
1182 4805600 : return !!(strcasecmp(str, "yes") == 0 ||
1183 1910938 : strcasecmp(str, "true") == 0 ||
1184 969578 : atoi(str));
1185 : }
1186 :
1187 : /**
1188 : * heim_config_get_bool() will convert the configuration
1189 : * option value to a boolean value, where yes/true and any non-zero
1190 : * number means TRUE and other value is FALSE.
1191 : *
1192 : * @param context A Kerberos 5 context.
1193 : * @param c a configuration section, or NULL to use the section from context
1194 : * @param args a va_list of arguments
1195 : *
1196 : * @return TRUE or FALSE
1197 : *
1198 : * @ingroup heim_support
1199 : */
1200 :
1201 : int
1202 0 : heim_config_vget_bool(heim_context context,
1203 : const heim_config_section *c,
1204 : va_list args)
1205 : {
1206 0 : return heim_config_vget_bool_default(context, c, 0, args);
1207 : }
1208 :
1209 : /**
1210 : * heim_config_get_bool_default() will convert the configuration
1211 : * option value to a boolean value, where yes/true and any non-zero
1212 : * number means TRUE and other value is FALSE.
1213 : *
1214 : * @param context A Kerberos 5 context.
1215 : * @param c a configuration section, or NULL to use the section from context
1216 : * @param def_value the default value to return if no configuration
1217 : * found in the database.
1218 : * @param ... a list of names, terminated with NULL.
1219 : *
1220 : * @return TRUE or FALSE
1221 : *
1222 : * @ingroup heim_support
1223 : */
1224 :
1225 : int
1226 0 : heim_config_get_bool_default(heim_context context,
1227 : const heim_config_section *c,
1228 : int def_value,
1229 : ...)
1230 : {
1231 : va_list ap;
1232 : int ret;
1233 :
1234 0 : va_start(ap, def_value);
1235 0 : ret = heim_config_vget_bool_default(context, c, def_value, ap);
1236 0 : va_end(ap);
1237 0 : return ret;
1238 : }
1239 :
1240 : /**
1241 : * Like heim_config_get_bool() but with a va_list list of
1242 : * configuration selection.
1243 : *
1244 : * Configuration value to a boolean value, where yes/true and any
1245 : * non-zero number means TRUE and other value is FALSE.
1246 : *
1247 : * @param context A Kerberos 5 context.
1248 : * @param c a configuration section, or NULL to use the section from context
1249 : * @param ... a list of names, terminated with NULL.
1250 : *
1251 : * @return TRUE or FALSE
1252 : *
1253 : * @ingroup heim_support
1254 : */
1255 :
1256 : int
1257 0 : heim_config_get_bool(heim_context context,
1258 : const heim_config_section *c,
1259 : ...)
1260 : {
1261 : va_list ap;
1262 : int ret;
1263 0 : va_start(ap, c);
1264 0 : ret = heim_config_vget_bool (context, c, ap);
1265 0 : va_end(ap);
1266 0 : return ret;
1267 : }
1268 :
1269 : /**
1270 : * Get the time from the configuration file using a relative time.
1271 : *
1272 : * Like heim_config_get_time_default() but with a va_list list of
1273 : * configuration selection.
1274 : *
1275 : * @param context A Kerberos 5 context.
1276 : * @param c a configuration section, or NULL to use the section from context
1277 : * @param def_value the default value to return if no configuration
1278 : * found in the database.
1279 : * @param args a va_list of arguments
1280 : *
1281 : * @return parsed the time (or def_value on parse error)
1282 : *
1283 : * @ingroup heim_support
1284 : */
1285 :
1286 : time_t
1287 3401849 : heim_config_vget_time_default(heim_context context,
1288 : const heim_config_section *c,
1289 : int def_value,
1290 : va_list args)
1291 : {
1292 : const char *str;
1293 3401849 : time_t t = -1;
1294 :
1295 3401849 : if ((str = heim_config_vget_string(context, c, args)))
1296 0 : t = parse_time(str, "s");
1297 3401849 : return t != -1 ? t : def_value;
1298 : }
1299 :
1300 : /**
1301 : * Get the time from the configuration file using a relative time, for example: 1h30s
1302 : *
1303 : * @param context A Kerberos 5 context.
1304 : * @param c a configuration section, or NULL to use the section from context
1305 : * @param args a va_list of arguments
1306 : *
1307 : * @return parsed the time or -1 on error
1308 : *
1309 : * @ingroup heim_support
1310 : */
1311 :
1312 : time_t
1313 16202 : heim_config_vget_time(heim_context context,
1314 : const heim_config_section *c,
1315 : va_list args)
1316 : {
1317 16202 : return heim_config_vget_time_default(context, c, -1, args);
1318 : }
1319 :
1320 : /**
1321 : * Get the time from the configuration file using a relative time, for example: 1h30s
1322 : *
1323 : * @param context A Kerberos 5 context.
1324 : * @param c a configuration section, or NULL to use the section from context
1325 : * @param def_value the default value to return if no configuration
1326 : * found in the database.
1327 : * @param ... a list of names, terminated with NULL.
1328 : *
1329 : * @return parsed the time (or def_value on parse error)
1330 : *
1331 : * @ingroup heim_support
1332 : */
1333 :
1334 : time_t
1335 555816 : heim_config_get_time_default(heim_context context,
1336 : const heim_config_section *c,
1337 : int def_value,
1338 : ...)
1339 : {
1340 : va_list ap;
1341 : time_t ret;
1342 :
1343 555816 : va_start(ap, def_value);
1344 555816 : ret = heim_config_vget_time_default(context, c, def_value, ap);
1345 555816 : va_end(ap);
1346 555816 : return ret;
1347 : }
1348 :
1349 : /**
1350 : * Get the time from the configuration file using a relative time, for example: 1h30s
1351 : *
1352 : * @param context A Kerberos 5 context.
1353 : * @param c a configuration section, or NULL to use the section from context
1354 : * @param ... a list of names, terminated with NULL.
1355 : *
1356 : * @return parsed the time or -1 on error
1357 : *
1358 : * @ingroup heim_support
1359 : */
1360 :
1361 : time_t
1362 0 : heim_config_get_time(heim_context context,
1363 : const heim_config_section *c,
1364 : ...)
1365 : {
1366 : va_list ap;
1367 : int ret;
1368 0 : va_start(ap, c);
1369 0 : ret = heim_config_vget_time(context, c, ap);
1370 0 : va_end(ap);
1371 0 : return ret;
1372 : }
1373 :
1374 :
1375 : int
1376 3772946 : heim_config_vget_int_default(heim_context context,
1377 : const heim_config_section *c,
1378 : int def_value,
1379 : va_list args)
1380 : {
1381 : const char *str;
1382 3772946 : str = heim_config_vget_string (context, c, args);
1383 3772946 : if(str == NULL)
1384 3772946 : return def_value;
1385 : else {
1386 : char *endptr;
1387 : long l;
1388 0 : l = strtol(str, &endptr, 0);
1389 0 : if (endptr == str)
1390 0 : return def_value;
1391 : else
1392 0 : return l;
1393 : }
1394 : }
1395 :
1396 : int
1397 0 : heim_config_vget_int(heim_context context,
1398 : const heim_config_section *c,
1399 : va_list args)
1400 : {
1401 0 : return heim_config_vget_int_default(context, c, -1, args);
1402 : }
1403 :
1404 : int
1405 0 : heim_config_get_int_default(heim_context context,
1406 : const heim_config_section *c,
1407 : int def_value,
1408 : ...)
1409 : {
1410 : va_list ap;
1411 : int ret;
1412 :
1413 0 : va_start(ap, def_value);
1414 0 : ret = heim_config_vget_int_default(context, c, def_value, ap);
1415 0 : va_end(ap);
1416 0 : return ret;
1417 : }
1418 :
1419 : int
1420 0 : heim_config_get_int(heim_context context,
1421 : const heim_config_section *c,
1422 : ...)
1423 : {
1424 : va_list ap;
1425 : int ret;
1426 0 : va_start(ap, c);
1427 0 : ret = heim_config_vget_int (context, c, ap);
1428 0 : va_end(ap);
1429 0 : return ret;
1430 : }
1431 :
1432 : #ifndef HEIMDAL_SMALLER
1433 : heim_error_code
1434 0 : heim_config_parse_string_multi(heim_context context,
1435 : const char *string,
1436 : heim_config_section **res)
1437 : {
1438 : const char *str;
1439 0 : unsigned lineno = 0;
1440 : heim_error_code ret;
1441 : struct fileptr f;
1442 :
1443 0 : f.context = context;
1444 0 : f.f = NULL;
1445 0 : f.s = string;
1446 :
1447 0 : ret = heim_config_parse_debug(&f, res, &lineno, &str);
1448 0 : if (ret) {
1449 0 : if (ret != HEIM_ERR_CONFIG_BADFORMAT) {
1450 0 : ret = HEIM_ERR_CONFIG_BADFORMAT;
1451 0 : heim_set_error_message(context, ret, "%s:%u: %s",
1452 : "<constant>", lineno, str);
1453 : }
1454 0 : return ret;
1455 : }
1456 0 : return 0;
1457 : }
1458 : #endif
|