This commit was manufactured by cvs2svn to create tag
[heimdal.git] / lib / krb5 / config_file.c
blob9415ede27cf84646ac66f3763eb8fa4961f850d6
1 /*
2 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "krb5_locl.h"
35 RCSID("$Id$");
37 #ifndef HAVE_NETINFO
39 static krb5_error_code parse_section(char *p, krb5_config_section **s,
40 krb5_config_section **res,
41 const char **error_message);
42 static krb5_error_code parse_binding(FILE *f, unsigned *lineno, char *p,
43 krb5_config_binding **b,
44 krb5_config_binding **parent,
45 const char **error_message);
46 static krb5_error_code parse_list(FILE *f, unsigned *lineno,
47 krb5_config_binding **parent,
48 const char **error_message);
50 static krb5_config_section *
51 get_entry(krb5_config_section **parent, const char *name, int type)
53 krb5_config_section **q;
55 for(q = parent; *q != NULL; q = &(*q)->next)
56 if(type == krb5_config_list &&
57 type == (*q)->type &&
58 strcmp(name, (*q)->name) == 0)
59 return *q;
60 *q = calloc(1, sizeof(**q));
61 if(*q == NULL)
62 return NULL;
63 (*q)->name = strdup(name);
64 (*q)->type = type;
65 if((*q)->name == NULL) {
66 free(*q);
67 *q = NULL;
68 return NULL;
70 return *q;
74 * Parse a section:
76 * [section]
77 * foo = bar
78 * b = {
79 * a
80 * }
81 * ...
83 * starting at the line in `p', storing the resulting structure in
84 * `s' and hooking it into `parent'.
85 * Store the error message in `error_message'.
88 static krb5_error_code
89 parse_section(char *p, krb5_config_section **s, krb5_config_section **parent,
90 const char **error_message)
92 char *p1;
93 krb5_config_section *tmp;
95 p1 = strchr (p + 1, ']');
96 if (p1 == NULL) {
97 *error_message = "missing ]";
98 return KRB5_CONFIG_BADFORMAT;
100 *p1 = '\0';
101 tmp = get_entry(parent, p + 1, krb5_config_list);
102 if(tmp == NULL) {
103 *error_message = "out of memory";
104 return KRB5_CONFIG_BADFORMAT;
106 *s = tmp;
107 return 0;
111 * Parse a brace-enclosed list from `f', hooking in the structure at
112 * `parent'.
113 * Store the error message in `error_message'.
116 static krb5_error_code
117 parse_list(FILE *f, unsigned *lineno, krb5_config_binding **parent,
118 const char **error_message)
120 char buf[BUFSIZ];
121 krb5_error_code ret;
122 krb5_config_binding *b = NULL;
123 unsigned beg_lineno = *lineno;
125 while(fgets(buf, sizeof(buf), f) != NULL) {
126 char *p;
128 ++*lineno;
129 if (buf[strlen(buf) - 1] == '\n')
130 buf[strlen(buf) - 1] = '\0';
131 p = buf;
132 while(isspace((unsigned char)*p))
133 ++p;
134 if (*p == '#' || *p == ';' || *p == '\0')
135 continue;
136 while(isspace((unsigned char)*p))
137 ++p;
138 if (*p == '}')
139 return 0;
140 if (*p == '\0')
141 continue;
142 ret = parse_binding (f, lineno, p, &b, parent, error_message);
143 if (ret)
144 return ret;
146 *lineno = beg_lineno;
147 *error_message = "unclosed {";
148 return KRB5_CONFIG_BADFORMAT;
155 static krb5_error_code
156 parse_binding(FILE *f, unsigned *lineno, char *p,
157 krb5_config_binding **b, krb5_config_binding **parent,
158 const char **error_message)
160 krb5_config_binding *tmp;
161 char *p1, *p2;
162 krb5_error_code ret = 0;
164 p1 = p;
165 while (*p && *p != '=' && !isspace((unsigned char)*p))
166 ++p;
167 if (*p == '\0') {
168 *error_message = "missing =";
169 return KRB5_CONFIG_BADFORMAT;
171 p2 = p;
172 while (isspace((unsigned char)*p))
173 ++p;
174 if (*p != '=') {
175 *error_message = "missing =";
176 return KRB5_CONFIG_BADFORMAT;
178 ++p;
179 while(isspace((unsigned char)*p))
180 ++p;
181 *p2 = '\0';
182 if (*p == '{') {
183 tmp = get_entry(parent, p1, krb5_config_list);
184 if (tmp == NULL) {
185 *error_message = "out of memory";
186 return KRB5_CONFIG_BADFORMAT;
188 ret = parse_list (f, lineno, &tmp->u.list, error_message);
189 } else {
190 tmp = get_entry(parent, p1, krb5_config_string);
191 if (tmp == NULL) {
192 *error_message = "out of memory";
193 return KRB5_CONFIG_BADFORMAT;
195 p1 = p;
196 p = p1 + strlen(p1);
197 while(p > p1 && isspace((unsigned char)*(p-1)))
198 --p;
199 *p = '\0';
200 tmp->u.string = strdup(p1);
202 *b = tmp;
203 return ret;
207 * Parse the config file `fname', generating the structures into `res'
208 * returning error messages in `error_message'
211 static krb5_error_code
212 krb5_config_parse_file_debug (const char *fname,
213 krb5_config_section **res,
214 unsigned *lineno,
215 const char **error_message)
217 FILE *f;
218 krb5_config_section *s;
219 krb5_config_binding *b;
220 char buf[BUFSIZ];
221 krb5_error_code ret = 0;
223 s = NULL;
224 b = NULL;
225 *lineno = 0;
226 f = fopen (fname, "r");
227 if (f == NULL) {
228 *error_message = "cannot open file";
229 return ENOENT;
231 while (fgets(buf, sizeof(buf), f) != NULL) {
232 char *p;
234 ++*lineno;
235 if(buf[strlen(buf) - 1] == '\n')
236 buf[strlen(buf) - 1] = '\0';
237 p = buf;
238 while(isspace((unsigned char)*p))
239 ++p;
240 if (*p == '#' || *p == ';')
241 continue;
242 if (*p == '[') {
243 ret = parse_section(p, &s, res, error_message);
244 if (ret) {
245 goto out;
247 b = NULL;
248 } else if (*p == '}') {
249 *error_message = "unmatched }";
250 ret = EINVAL; /* XXX */
251 goto out;
252 } else if(*p != '\0') {
253 if (s == NULL) {
254 *error_message = "binding before section";
255 ret = EINVAL;
256 goto out;
258 ret = parse_binding(f, lineno, p, &b, &s->u.list, error_message);
259 if (ret)
260 goto out;
263 out:
264 fclose (f);
265 return ret;
268 krb5_error_code
269 krb5_config_parse_file_multi (krb5_context context,
270 const char *fname,
271 krb5_config_section **res)
273 const char *str;
274 unsigned lineno;
275 krb5_error_code ret;
277 ret = krb5_config_parse_file_debug (fname, res, &lineno, &str);
278 if (ret) {
279 krb5_set_error_string (context, "%s:%u: %s", fname, lineno, str);
280 return ret;
282 return 0;
285 krb5_error_code
286 krb5_config_parse_file (krb5_context context,
287 const char *fname,
288 krb5_config_section **res)
290 *res = NULL;
291 return krb5_config_parse_file_multi(context, fname, res);
294 #endif /* !HAVE_NETINFO */
296 static void
297 free_binding (krb5_context context, krb5_config_binding *b)
299 krb5_config_binding *next_b;
301 while (b) {
302 free (b->name);
303 if (b->type == krb5_config_string)
304 free (b->u.string);
305 else if (b->type == krb5_config_list)
306 free_binding (context, b->u.list);
307 else
308 krb5_abortx(context, "unknown binding type (%d) in free_binding",
309 b->type);
310 next_b = b->next;
311 free (b);
312 b = next_b;
316 krb5_error_code
317 krb5_config_file_free (krb5_context context, krb5_config_section *s)
319 free_binding (context, s);
320 return 0;
323 const void *
324 krb5_config_get_next (krb5_context context,
325 const krb5_config_section *c,
326 const krb5_config_binding **pointer,
327 int type,
328 ...)
330 const char *ret;
331 va_list args;
333 va_start(args, type);
334 ret = krb5_config_vget_next (context, c, pointer, type, args);
335 va_end(args);
336 return ret;
339 static const void *
340 vget_next(krb5_context context,
341 const krb5_config_binding *b,
342 const krb5_config_binding **pointer,
343 int type,
344 const char *name,
345 va_list args)
347 const char *p = va_arg(args, const char *);
348 while(b != NULL) {
349 if(strcmp(b->name, name) == 0) {
350 if(b->type == type && p == NULL) {
351 *pointer = b;
352 return b->u.generic;
353 } else if(b->type == krb5_config_list && p != NULL) {
354 return vget_next(context, b->u.list, pointer, type, p, args);
357 b = b->next;
359 return NULL;
362 const void *
363 krb5_config_vget_next (krb5_context context,
364 const krb5_config_section *c,
365 const krb5_config_binding **pointer,
366 int type,
367 va_list args)
369 const krb5_config_binding *b;
370 const char *p;
372 if(c == NULL)
373 c = context->cf;
375 if (c == NULL)
376 return NULL;
378 if (*pointer == NULL) {
379 /* first time here, walk down the tree looking for the right
380 section */
381 p = va_arg(args, const char *);
382 if (p == NULL)
383 return NULL;
384 return vget_next(context, c, pointer, type, p, args);
387 /* we were called again, so just look for more entries with the
388 same name and type */
389 for (b = (*pointer)->next; b != NULL; b = b->next) {
390 if(strcmp(b->name, (*pointer)->name) == 0 && b->type == type) {
391 *pointer = b;
392 return b->u.generic;
395 return NULL;
398 const void *
399 krb5_config_get (krb5_context context,
400 const krb5_config_section *c,
401 int type,
402 ...)
404 const void *ret;
405 va_list args;
407 va_start(args, type);
408 ret = krb5_config_vget (context, c, type, args);
409 va_end(args);
410 return ret;
413 const void *
414 krb5_config_vget (krb5_context context,
415 const krb5_config_section *c,
416 int type,
417 va_list args)
419 const krb5_config_binding *foo = NULL;
421 return krb5_config_vget_next (context, c, &foo, type, args);
424 const krb5_config_binding *
425 krb5_config_get_list (krb5_context context,
426 const krb5_config_section *c,
427 ...)
429 const krb5_config_binding *ret;
430 va_list args;
432 va_start(args, c);
433 ret = krb5_config_vget_list (context, c, args);
434 va_end(args);
435 return ret;
438 const krb5_config_binding *
439 krb5_config_vget_list (krb5_context context,
440 const krb5_config_section *c,
441 va_list args)
443 return krb5_config_vget (context, c, krb5_config_list, args);
446 const char *
447 krb5_config_get_string (krb5_context context,
448 const krb5_config_section *c,
449 ...)
451 const char *ret;
452 va_list args;
454 va_start(args, c);
455 ret = krb5_config_vget_string (context, c, args);
456 va_end(args);
457 return ret;
460 const char *
461 krb5_config_vget_string (krb5_context context,
462 const krb5_config_section *c,
463 va_list args)
465 return krb5_config_vget (context, c, krb5_config_string, args);
468 const char *
469 krb5_config_vget_string_default (krb5_context context,
470 const krb5_config_section *c,
471 const char *def_value,
472 va_list args)
474 const char *ret;
476 ret = krb5_config_vget_string (context, c, args);
477 if (ret == NULL)
478 ret = def_value;
479 return ret;
482 const char *
483 krb5_config_get_string_default (krb5_context context,
484 const krb5_config_section *c,
485 const char *def_value,
486 ...)
488 const char *ret;
489 va_list args;
491 va_start(args, def_value);
492 ret = krb5_config_vget_string_default (context, c, def_value, args);
493 va_end(args);
494 return ret;
497 char **
498 krb5_config_vget_strings(krb5_context context,
499 const krb5_config_section *c,
500 va_list args)
502 char **strings = NULL;
503 int nstr = 0;
504 const krb5_config_binding *b = NULL;
505 const char *p;
507 while((p = krb5_config_vget_next(context, c, &b,
508 krb5_config_string, args))) {
509 char *tmp = strdup(p);
510 char *pos = NULL;
511 char *s;
512 if(tmp == NULL)
513 goto cleanup;
514 s = strtok_r(tmp, " \t", &pos);
515 while(s){
516 char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings));
517 if(tmp == NULL)
518 goto cleanup;
519 strings = tmp;
520 strings[nstr] = strdup(s);
521 nstr++;
522 if(strings[nstr-1] == NULL)
523 goto cleanup;
524 s = strtok_r(NULL, " \t", &pos);
526 free(tmp);
528 if(nstr){
529 char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings));
530 if(strings == NULL)
531 goto cleanup;
532 strings = tmp;
533 strings[nstr] = NULL;
535 return strings;
536 cleanup:
537 while(nstr--)
538 free(strings[nstr]);
539 free(strings);
540 return NULL;
544 char**
545 krb5_config_get_strings(krb5_context context,
546 const krb5_config_section *c,
547 ...)
549 va_list ap;
550 char **ret;
551 va_start(ap, c);
552 ret = krb5_config_vget_strings(context, c, ap);
553 va_end(ap);
554 return ret;
557 void
558 krb5_config_free_strings(char **strings)
560 char **s = strings;
561 while(s && *s){
562 free(*s);
563 s++;
565 free(strings);
568 krb5_boolean
569 krb5_config_vget_bool_default (krb5_context context,
570 const krb5_config_section *c,
571 krb5_boolean def_value,
572 va_list args)
574 const char *str;
575 str = krb5_config_vget_string (context, c, args);
576 if(str == NULL)
577 return def_value;
578 if(strcasecmp(str, "yes") == 0 ||
579 strcasecmp(str, "true") == 0 ||
580 atoi(str)) return TRUE;
581 return FALSE;
584 krb5_boolean
585 krb5_config_vget_bool (krb5_context context,
586 const krb5_config_section *c,
587 va_list args)
589 return krb5_config_vget_bool_default (context, c, FALSE, args);
592 krb5_boolean
593 krb5_config_get_bool_default (krb5_context context,
594 const krb5_config_section *c,
595 krb5_boolean def_value,
596 ...)
598 va_list ap;
599 krb5_boolean ret;
600 va_start(ap, def_value);
601 ret = krb5_config_vget_bool_default(context, c, def_value, ap);
602 va_end(ap);
603 return ret;
606 krb5_boolean
607 krb5_config_get_bool (krb5_context context,
608 const krb5_config_section *c,
609 ...)
611 va_list ap;
612 krb5_boolean ret;
613 va_start(ap, c);
614 ret = krb5_config_vget_bool (context, c, ap);
615 va_end(ap);
616 return ret;
620 krb5_config_vget_time_default (krb5_context context,
621 const krb5_config_section *c,
622 int def_value,
623 va_list args)
625 const char *str;
626 str = krb5_config_vget_string (context, c, args);
627 if(str == NULL)
628 return def_value;
629 return parse_time (str, NULL);
633 krb5_config_vget_time (krb5_context context,
634 const krb5_config_section *c,
635 va_list args)
637 return krb5_config_vget_time_default (context, c, -1, args);
641 krb5_config_get_time_default (krb5_context context,
642 const krb5_config_section *c,
643 int def_value,
644 ...)
646 va_list ap;
647 int ret;
648 va_start(ap, def_value);
649 ret = krb5_config_vget_time_default(context, c, def_value, ap);
650 va_end(ap);
651 return ret;
655 krb5_config_get_time (krb5_context context,
656 const krb5_config_section *c,
657 ...)
659 va_list ap;
660 int ret;
661 va_start(ap, c);
662 ret = krb5_config_vget_time (context, c, ap);
663 va_end(ap);
664 return ret;
669 krb5_config_vget_int_default (krb5_context context,
670 const krb5_config_section *c,
671 int def_value,
672 va_list args)
674 const char *str;
675 str = krb5_config_vget_string (context, c, args);
676 if(str == NULL)
677 return def_value;
678 else {
679 char *endptr;
680 long l;
681 l = strtol(str, &endptr, 0);
682 if (endptr == str)
683 return def_value;
684 else
685 return l;
690 krb5_config_vget_int (krb5_context context,
691 const krb5_config_section *c,
692 va_list args)
694 return krb5_config_vget_int_default (context, c, -1, args);
698 krb5_config_get_int_default (krb5_context context,
699 const krb5_config_section *c,
700 int def_value,
701 ...)
703 va_list ap;
704 int ret;
705 va_start(ap, def_value);
706 ret = krb5_config_vget_int_default(context, c, def_value, ap);
707 va_end(ap);
708 return ret;
712 krb5_config_get_int (krb5_context context,
713 const krb5_config_section *c,
714 ...)
716 va_list ap;
717 int ret;
718 va_start(ap, c);
719 ret = krb5_config_vget_int (context, c, ap);
720 va_end(ap);
721 return ret;