c258a2bd3b996579bee3123edd12b27c35b86e01
[samba.git] / source4 / heimdal / lib / krb5 / verify_krb5_conf.c
1 /*
2  * Copyright (c) 1999 - 2005 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "krb5_locl.h"
35 #include <getarg.h>
36 #include <parse_bytes.h>
37 #include <err.h>
38
39 /* verify krb5.conf */
40 static int dumpconfig_flag = 0;
41 static int version_flag = 0;
42 static int help_flag    = 0;
43 static int warn_mit_syntax_flag = 0;
44
45 static struct getargs args[] = {
46     {"dumpconfig", 0,      arg_flag,       &dumpconfig_flag,
47      "show the parsed config files", NULL },
48     {"warn-mit-syntax", 0, arg_flag,       &warn_mit_syntax_flag,
49      "show the parsed config files", NULL },
50     {"version", 0,      arg_flag,       &version_flag,
51      "print version", NULL },
52     {"help",    0,      arg_flag,       &help_flag,
53      NULL, NULL }
54 };
55
56 static void
57 usage (int ret)
58 {
59     arg_printusage (args,
60                     sizeof(args)/sizeof(*args),
61                     NULL,
62                     "[config-file]");
63     exit (ret);
64 }
65
66 static int
67 check_bytes(krb5_context context, const char *path, char *data)
68 {
69     if(parse_bytes(data, NULL) == -1) {
70         krb5_warnx(context, "%s: failed to parse \"%s\" as size", path, data);
71         return 1;
72     }
73     return 0;
74 }
75
76 static int
77 check_time(krb5_context context, const char *path, char *data)
78 {
79     if(parse_time(data, NULL) == -1) {
80         krb5_warnx(context, "%s: failed to parse \"%s\" as time", path, data);
81         return 1;
82     }
83     return 0;
84 }
85
86 static int
87 check_numeric(krb5_context context, const char *path, char *data)
88 {
89     long v;
90     char *end;
91     v = strtol(data, &end, 0);
92
93     if ((v == LONG_MIN || v == LONG_MAX) && errno != 0) {
94         krb5_warnx(context, "%s: over/under flow for \"%s\"",
95                    path, data);
96         return 1;
97     }
98     if(*end != '\0') {
99         krb5_warnx(context, "%s: failed to parse \"%s\" as a number",
100                    path, data);
101         return 1;
102     }
103     return 0;
104 }
105
106 static int
107 check_boolean(krb5_context context, const char *path, char *data)
108 {
109     long int v;
110     char *end;
111     if(strcasecmp(data, "yes") == 0 ||
112        strcasecmp(data, "true") == 0 ||
113        strcasecmp(data, "no") == 0 ||
114        strcasecmp(data, "false") == 0)
115         return 0;
116     v = strtol(data, &end, 0);
117     if(*end != '\0') {
118         krb5_warnx(context, "%s: failed to parse \"%s\" as a boolean",
119                    path, data);
120         return 1;
121     }
122     if(v != 0 && v != 1)
123         krb5_warnx(context, "%s: numeric value \"%s\" is treated as \"true\"",
124                    path, data);
125     return 0;
126 }
127
128 static int
129 check_524(krb5_context context, const char *path, char *data)
130 {
131     if(strcasecmp(data, "yes") == 0 ||
132        strcasecmp(data, "no") == 0 ||
133        strcasecmp(data, "2b") == 0 ||
134        strcasecmp(data, "local") == 0)
135         return 0;
136
137     krb5_warnx(context, "%s: didn't contain a valid option `%s'",
138                path, data);
139     return 1;
140 }
141
142 static int
143 check_host(krb5_context context, const char *path, char *data)
144 {
145     int ret;
146     char hostname[128];
147     const char *p = data;
148     struct addrinfo hints;
149     char service[32];
150     int defport;
151     struct addrinfo *ai;
152
153     hints.ai_flags = 0;
154     hints.ai_family = PF_UNSPEC;
155     hints.ai_socktype = 0;
156     hints.ai_protocol = 0;
157
158     hints.ai_addrlen = 0;
159     hints.ai_canonname = NULL;
160     hints.ai_addr = NULL;
161     hints.ai_next = NULL;
162
163     /* XXX data could be a list of hosts that this code can't handle */
164     /* XXX copied from krbhst.c */
165     if (strncmp(p, "http://", 7) == 0){
166         p += 7;
167         hints.ai_socktype = SOCK_STREAM;
168         strlcpy(service, "http", sizeof(service));
169         defport = 80;
170     } else if (strncmp(p, "http/", 5) == 0) {
171         p += 5;
172         hints.ai_socktype = SOCK_STREAM;
173         strlcpy(service, "http", sizeof(service));
174         defport = 80;
175     } else if (strncmp(p, "tcp/", 4) == 0){
176         p += 4;
177         hints.ai_socktype = SOCK_STREAM;
178         strlcpy(service, "kerberos", sizeof(service));
179         defport = 88;
180     } else if (strncmp(p, "udp/", 4) == 0) {
181         p += 4;
182         hints.ai_socktype = SOCK_DGRAM;
183         strlcpy(service, "kerberos", sizeof(service));
184         defport = 88;
185     } else {
186         hints.ai_socktype = SOCK_DGRAM;
187         strlcpy(service, "kerberos", sizeof(service));
188         defport = 88;
189     }
190     if (strsep_copy(&p, ":", hostname, sizeof(hostname)) < 0) {
191         return 1;
192     }
193     hostname[strcspn(hostname, "/")] = '\0';
194     if (p != NULL) {
195         char *end;
196         int tmp = strtol(p, &end, 0);
197         if (end == p) {
198             krb5_warnx(context, "%s: failed to parse port number in %s",
199                        path, data);
200             return 1;
201         }
202         defport = tmp;
203         snprintf(service, sizeof(service), "%u", defport);
204     }
205     ret = getaddrinfo(hostname, service, &hints, &ai);
206     if (ret == EAI_SERVICE && !isdigit((unsigned char)service[0])) {
207         snprintf(service, sizeof(service), "%u", defport);
208         ret = getaddrinfo(hostname, service, &hints, &ai);
209     }
210     if (ret != 0) {
211         krb5_warnx(context, "%s: %s (%s)", path, gai_strerror(ret), hostname);
212         return 1;
213     }
214     freeaddrinfo(ai);
215     return 0;
216 }
217
218 static int
219 check_directory(krb5_context context, const char *path, char *data)
220 {
221     DIR *d = opendir(data);
222     if (d == NULL) {
223         krb5_warn(context, errno, "%s: could not open directory `%s'",
224                   path, data);
225         return 1;
226     }
227
228     closedir(d);
229     return 0;
230 }
231
232 static int
233 mit_entry(krb5_context context, const char *path, char *data)
234 {
235     if (warn_mit_syntax_flag)
236         krb5_warnx(context, "%s is only used by MIT Kerberos", path);
237     return 0;
238 }
239
240 struct s2i {
241     const char *s;
242     int val;
243 };
244
245 #define L(X) { #X, LOG_ ## X }
246
247 static struct s2i syslogvals[] = {
248     /* severity */
249     L(EMERG),
250     L(ALERT),
251     L(CRIT),
252     L(ERR),
253     L(WARNING),
254     L(NOTICE),
255     L(INFO),
256     L(DEBUG),
257     /* facility */
258     L(AUTH),
259 #ifdef LOG_AUTHPRIV
260     L(AUTHPRIV),
261 #endif
262 #ifdef LOG_CRON
263     L(CRON),
264 #endif
265     L(DAEMON),
266 #ifdef LOG_FTP
267     L(FTP),
268 #endif
269     L(KERN),
270     L(LPR),
271     L(MAIL),
272 #ifdef LOG_NEWS
273     L(NEWS),
274 #endif
275     L(SYSLOG),
276     L(USER),
277 #ifdef LOG_UUCP
278     L(UUCP),
279 #endif
280     L(LOCAL0),
281     L(LOCAL1),
282     L(LOCAL2),
283     L(LOCAL3),
284     L(LOCAL4),
285     L(LOCAL5),
286     L(LOCAL6),
287     L(LOCAL7),
288     { NULL, -1 }
289 };
290
291 static int
292 find_value(const char *s, struct s2i *table)
293 {
294     while (table->s && strcasecmp(table->s, s) != 0)
295         table++;
296     return table->val;
297 }
298
299 static int
300 check_log(krb5_context context, const char *path, char *data)
301 {
302     /* XXX sync with log.c */
303     int min = 0, max = -1, n;
304     char c;
305     const char *p = data;
306 #ifdef _WIN32
307     const char *q;
308 #endif
309
310     n = sscanf(p, "%d%c%d/", &min, &c, &max);
311     if(n == 2){
312         if(ISPATHSEP(c)) {
313             if(min < 0){
314                 max = -min;
315                 min = 0;
316             }else{
317                 max = min;
318             }
319         }
320     }
321     if(n){
322 #ifdef _WIN32
323         q = strrchr(p, '\\');
324         if (q != NULL)
325             p = q;
326         else
327 #endif
328         p = strchr(p, '/');
329         if(p == NULL) {
330             krb5_warnx(context, "%s: failed to parse \"%s\"", path, data);
331             return 1;
332         }
333         p++;
334     }
335     if(strcmp(p, "STDERR") == 0 ||
336        strcmp(p, "CONSOLE") == 0 ||
337        (strncmp(p, "FILE", 4) == 0 && (p[4] == ':' || p[4] == '=')) ||
338        (strncmp(p, "DEVICE", 6) == 0 && p[6] == '='))
339         return 0;
340     if(strncmp(p, "SYSLOG", 6) == 0){
341         int ret = 0;
342         char severity[128] = "";
343         char facility[128] = "";
344         p += 6;
345         if(*p != '\0')
346             p++;
347         if(strsep_copy(&p, ":", severity, sizeof(severity)) != -1)
348             strsep_copy(&p, ":", facility, sizeof(facility));
349         if(*severity == '\0')
350             strlcpy(severity, "ERR", sizeof(severity));
351         if(*facility == '\0')
352             strlcpy(facility, "AUTH", sizeof(facility));
353         if(find_value(facility, syslogvals) == -1) {
354             krb5_warnx(context, "%s: unknown syslog facility \"%s\"",
355                        path, facility);
356             ret++;
357         }
358         if(find_value(severity, syslogvals) == -1) {
359             krb5_warnx(context, "%s: unknown syslog severity \"%s\"",
360                        path, severity);
361             ret++;
362         }
363         return ret;
364     }else{
365         krb5_warnx(context, "%s: unknown log type: \"%s\"", path, data);
366         return 1;
367     }
368 }
369
370 typedef int (*check_func_t)(krb5_context, const char*, char*);
371 struct entry {
372     const char *name;
373     int type;
374     void *check_data;
375     int deprecated;
376 };
377
378 struct entry all_strings[] = {
379     { "", krb5_config_string, NULL, 0 },
380     { NULL, 0, NULL, 0 }
381 };
382
383 struct entry all_boolean[] = {
384     { "", krb5_config_string, check_boolean, 0 },
385     { NULL, 0, NULL, 0 }
386 };
387
388
389 struct entry v4_name_convert_entries[] = {
390     { "host", krb5_config_list, all_strings, 0 },
391     { "plain", krb5_config_list, all_strings, 0 },
392     { NULL, 0, NULL, 0 }
393 };
394
395 struct entry libdefaults_entries[] = {
396     { "accept_null_addresses", krb5_config_string, check_boolean, 0 },
397     { "allow_weak_crypto", krb5_config_string, check_boolean, 0 },
398     { "capath", krb5_config_list, all_strings, 1 },
399     { "ccapi_library", krb5_config_string, NULL, 0 },
400     { "check_pac", krb5_config_string, check_boolean, 0 },
401     { "check-rd-req-server", krb5_config_string, check_boolean, 0 },
402     { "clockskew", krb5_config_string, check_time, 0 },
403     { "date_format", krb5_config_string, NULL, 0 },
404     { "default_as_etypes", krb5_config_string, NULL, 0 },
405     { "default_ccache_name", krb5_config_string, NULL, 0 },
406     { "default_client_keytab_name", krb5_config_string, NULL, 0 },
407     { "default_cc_name", krb5_config_string, NULL, 0 },
408     { "default_cc_type", krb5_config_string, NULL, 0 },
409     { "default_cc_collection", krb5_config_string, NULL, 0 },
410     { "default_etypes", krb5_config_string, NULL, 0 },
411     { "default_etypes_des", krb5_config_string, NULL, 0 },
412     { "default_keytab_modify_name", krb5_config_string, NULL, 0 },
413     { "default_keytab_name", krb5_config_string, NULL, 0 },
414     { "default_keytab_modify_name", krb5_config_string, NULL, 0 },
415     { "default_realm", krb5_config_string, NULL, 0 },
416     { "default_tgs_etypes", krb5_config_string, NULL, 0 },
417     { "dns_canonicalize_hostname", krb5_config_string, check_boolean, 0 },
418     { "dns_proxy", krb5_config_string, NULL, 0 },
419     { "dns_lookup_kdc", krb5_config_string, check_boolean, 0 },
420     { "dns_lookup_realm", krb5_config_string, check_boolean, 0 },
421     { "dns_lookup_realm_labels", krb5_config_string, NULL, 0 },
422     { "egd_socket", krb5_config_string, NULL, 0 },
423     { "encrypt", krb5_config_string, check_boolean, 0 },
424     { "extra_addresses", krb5_config_string, NULL, 0 },
425     { "fcache_version", krb5_config_string, check_numeric, 0 },
426     { "fcache_strict_checking", krb5_config_string, check_boolean, 0 },
427     { "fcc-mit-ticketflags", krb5_config_string, check_boolean, 0 },
428     { "forward", krb5_config_string, check_boolean, 0 },
429     { "forwardable", krb5_config_string, check_boolean, 0 },
430     { "allow_hierarchical_capaths", krb5_config_string, check_boolean, 0 },
431     { "host_timeout", krb5_config_string, check_time, 0 },
432     { "http_proxy", krb5_config_string, check_host /* XXX */, 0 },
433     { "ignore_addresses", krb5_config_string, NULL, 0 },
434     { "k5login_authoritative", krb5_config_string, check_boolean, 0 },
435     { "k5login_directory", krb5_config_string, NULL, 0 },
436     { "kdc_timeout", krb5_config_string, check_time, 0 },
437     { "kdc_timesync", krb5_config_string, check_boolean, 0 },
438     { "kuserok", krb5_config_string, NULL, 0 },
439     { "large_message_size", krb5_config_string, check_numeric, 0 },
440     { "log_utc", krb5_config_string, check_boolean, 0 },
441     { "max_retries", krb5_config_string, check_numeric, 0 },
442     { "maximum_message_size", krb5_config_string, check_numeric, 0 },
443     { "moduli", krb5_config_string, NULL, 0 },
444     { "name_canon_rules", krb5_config_string, NULL, 0 },
445     { "no-addresses", krb5_config_string, check_boolean, 0 },
446     { "pkinit_dh_min_bits", krb5_config_string, NULL, 0 },
447     { "plugin_dir", krb5_config_string, check_directory, 0 },
448     { "proxiable", krb5_config_string, check_boolean, 0 },
449     { "renew_lifetime", krb5_config_string, check_time, 0 },
450     { "scan_interfaces", krb5_config_string, check_boolean, 0 },
451     { "srv_lookup", krb5_config_string, check_boolean, 0 },
452     { "srv_try_txt", krb5_config_string, check_boolean, 0 },
453     { "ticket_lifetime", krb5_config_string, check_time, 0 },
454     { "time_format", krb5_config_string, NULL, 0 },
455     { "transited_realms_reject", krb5_config_string, NULL, 0 },
456     { "use_fallback", krb5_config_string, check_boolean, 0 },
457     { "v4_instance_resolve", krb5_config_string, check_boolean, 0 },
458     { "v4_name_convert", krb5_config_list, v4_name_convert_entries, 0 },
459     { "verify_ap_req_nofail", krb5_config_string, check_boolean, 0 },
460     { "warn_pwexpire", krb5_config_string, check_time, 0 },
461
462     /* MIT stuff */
463     { "permitted_enctypes", krb5_config_string, mit_entry, 0 },
464     { "default_tgs_enctypes", krb5_config_string, mit_entry, 0 },
465     { "default_tkt_enctypes", krb5_config_string, mit_entry, 0 },
466     { NULL, 0, NULL, 0 }
467 };
468
469 struct entry appdefaults_entries[] = {
470     { "afslog", krb5_config_string, check_boolean, 0 },
471     { "afs-use-524", krb5_config_string, check_524, 0 },
472 #if 0
473     { "anonymous", krb5_config_string, check_boolean, 0 },
474 #endif
475     { "encrypt", krb5_config_string, check_boolean, 0 },
476     { "forward", krb5_config_string, check_boolean, 0 },
477     { "forwardable", krb5_config_string, check_boolean, 0 },
478     { "krb4_get_tickets", krb5_config_string, check_boolean, 0 },
479     { "proxiable", krb5_config_string, check_boolean, 0 },
480     { "renew_lifetime", krb5_config_string, check_time, 0 },
481     { "no-addresses", krb5_config_string, check_boolean, 0 },
482     { "pkinit_anchors", krb5_config_string, NULL, 0 },
483     { "pkinit_pool", krb5_config_string, NULL, 0 },
484     { "pkinit_require_eku", krb5_config_string, NULL, 0 },
485     { "pkinit_require_hostname_match", krb5_config_string, NULL, 0 },
486     { "pkinit_require_krbtgt_otherName", krb5_config_string, NULL, 0 },
487     { "pkinit_revoke", krb5_config_string, NULL, 0 },
488     { "pkinit_trustedCertifiers", krb5_config_string, check_boolean, 0 },
489     { "pkinit_win2k", krb5_config_string, NULL, 0 },
490     { "pkinit_win2k_require_binding", krb5_config_string, NULL, 0 },
491     { "ticket_lifetime", krb5_config_string, check_time, 0 },
492     { "", krb5_config_list, appdefaults_entries, 0 },
493     { NULL, 0, NULL, 0 }
494 };
495
496 struct entry realms_entries[] = {
497     { "admin_server", krb5_config_string, check_host, 0 },
498     { "auth_to_local", krb5_config_string, NULL, 0 },
499     { "auth_to_local_names", krb5_config_string, NULL, 0 },
500     { "default_domain", krb5_config_string, NULL, 0 },
501     { "forwardable", krb5_config_string, check_boolean, 0 },
502     { "allow_hierarchical_capaths", krb5_config_string, check_boolean, 0 },
503     { "kdc", krb5_config_string, check_host, 0 },
504     { "kpasswd_server", krb5_config_string, check_host, 0 },
505     { "krb524_server", krb5_config_string, check_host, 0 },
506     { "kx509_ca", krb5_config_string, NULL, 0 },
507     { "kx509_include_pkinit_san", krb5_config_string, check_boolean, 0 },
508     { "name_canon_rules", krb5_config_string, NULL, 0 },
509     { "no-addresses", krb5_config_string, check_boolean, 0 },
510     { "pkinit_anchors", krb5_config_string, NULL, 0 },
511     { "pkinit_require_eku", krb5_config_string, NULL, 0 },
512     { "pkinit_require_hostname_match", krb5_config_string, NULL, 0 },
513     { "pkinit_require_krbtgt_otherName", krb5_config_string, NULL, 0 },
514     { "pkinit_trustedCertifiers", krb5_config_string, check_boolean, 0 },
515     { "pkinit_win2k", krb5_config_string, NULL, 0 },
516     { "pkinit_win2k_require_binding", krb5_config_string, NULL, 0 },
517     { "proxiable", krb5_config_string, check_boolean, 0 },
518     { "renew_lifetime", krb5_config_string, check_time, 0 },
519     { "require_initial_kca_tickets", krb5_config_string, check_boolean, 0 },
520     { "ticket_lifetime", krb5_config_string, check_time, 0 },
521     { "v4_domains", krb5_config_string, NULL, 0 },
522     { "v4_instance_convert", krb5_config_list, all_strings, 0 },
523     { "v4_name_convert", krb5_config_list, v4_name_convert_entries, 0 },
524     { "warn_pwexpire", krb5_config_string, check_time, 0 },
525     { "win2k_pkinit", krb5_config_string, NULL, 0 },
526
527     /* MIT stuff */
528     { "admin_keytab", krb5_config_string, mit_entry, 0 },
529     { "acl_file", krb5_config_string, mit_entry, 0 },
530     { "database_name", krb5_config_string, mit_entry, 0 },
531     { "default_principal_expiration", krb5_config_string, mit_entry, 0 },
532     { "default_principal_flags", krb5_config_string, mit_entry, 0 },
533     { "dict_file", krb5_config_string, mit_entry, 0 },
534     { "kadmind_port", krb5_config_string, mit_entry, 0 },
535     { "kpasswd_port", krb5_config_string, mit_entry, 0 },
536     { "master_kdc", krb5_config_string, mit_entry, 0 },
537     { "master_key_name", krb5_config_string, mit_entry, 0 },
538     { "master_key_type", krb5_config_string, mit_entry, 0 },
539     { "key_stash_file", krb5_config_string, mit_entry, 0 },
540     { "max_life", krb5_config_string, mit_entry, 0 },
541     { "max_renewable_life", krb5_config_string, mit_entry, 0 },
542     { "supported_enctypes", krb5_config_string, mit_entry, 0 },
543     { NULL, 0, NULL, 0 }
544 };
545
546 struct entry realms_foobar[] = {
547     { "", krb5_config_list, realms_entries, 0 },
548     { NULL, 0, NULL, 0 }
549 };
550
551
552 struct entry kdc_database_entries[] = {
553     { "acl_file", krb5_config_string, NULL, 0 },
554     { "dbname", krb5_config_string, NULL, 0 },
555     { "log_file", krb5_config_string, NULL, 0 },
556     { "mkey_file", krb5_config_string, NULL, 0 },
557     { "realm", krb5_config_string, NULL, 0 },
558     { NULL, 0, NULL, 0 }
559 };
560
561 struct entry kdc_entries[] = {
562     { "addresses", krb5_config_string, NULL, 0 },
563     { "allow-anonymous", krb5_config_string, check_boolean, 0 },
564     { "allow-null-ticket-addresses", krb5_config_string, check_boolean, 0 },
565     { "check-ticket-addresses", krb5_config_string, check_boolean, 0 },
566     { "database", krb5_config_list, kdc_database_entries, 0 },
567     { "detach", krb5_config_string, check_boolean, 0 },
568     { "digests_allowed", krb5_config_string, NULL, 0 },
569     { "disable-des", krb5_config_string, check_boolean, 0 },
570     { "enable-524", krb5_config_string, check_boolean, 0 },
571     { "enable-digest", krb5_config_string, check_boolean, 0 },
572     { "enable-kaserver", krb5_config_string, check_boolean, 1 },
573     { "enable-kerberos4", krb5_config_string, check_boolean, 1 },
574     { "enable-kx509", krb5_config_string, check_boolean, 0 },
575     { "enable-http", krb5_config_string, check_boolean, 0 },
576     { "enable-pkinit", krb5_config_string, check_boolean, 0 },
577     { "encode_as_rep_as_tgs_rep", krb5_config_string, check_boolean, 0 },
578     { "enforce-transited-policy", krb5_config_string, NULL, 1 },
579     { "hdb-ldap-create-base", krb5_config_string, NULL, 0 },
580     { "iprop-acl", krb5_config_string, NULL, 0 },
581     { "iprop-stats", krb5_config_string, NULL, 0 },
582     { "kdc-request-log", krb5_config_string, NULL, 0 },
583     { "kdc_warn_pwexpire", krb5_config_string, check_time, 0 },
584     { "key-file", krb5_config_string, NULL, 0 },
585     { "kx509_ca", krb5_config_string, NULL, 0 },
586     { "kx509_include_pkinit_san", krb5_config_string, check_boolean, 0 },
587     { "kx509_template", krb5_config_string, NULL, 0 },
588     { "logging", krb5_config_string, check_log, 0 },
589     { "max-kdc-datagram-reply-length", krb5_config_string, check_bytes, 0 },
590     { "max-request", krb5_config_string, check_bytes, 0 },
591     { "num-kdc-processes", krb5_config_string, check_numeric, 0 },
592     { "pkinit_allow_proxy_certificate", krb5_config_string, check_boolean, 0 },
593     { "pkinit_anchors", krb5_config_string, NULL, 0 },
594     { "pkinit_dh_min_bits", krb5_config_string, check_numeric, 0 },
595     { "pkinit_identity", krb5_config_string, NULL, 0 },
596     { "pkinit_kdc_friendly_name", krb5_config_string, NULL, 0 },
597     { "pkinit_kdc_ocsp", krb5_config_string, NULL, 0 },
598     { "pkinit_mappings_file", krb5_config_string, NULL, 0 },
599     { "pkinit_pool", krb5_config_string, NULL, 0 },
600     { "pkinit_principal_in_certificate", krb5_config_string, check_boolean, 0 },
601     { "pkinit_revoke", krb5_config_string, NULL, 0 },
602     { "pkinit_win2k_require_binding", krb5_config_string, check_boolean, 0 },
603     { "ports", krb5_config_string, NULL, 0 },
604     { "preauth-use-strongest-session-key", krb5_config_string, check_boolean, 0 },
605     { "require_initial_kca_tickets", krb5_config_string, check_boolean, 0 },
606     { "require-preauth", krb5_config_string, check_boolean, 0 },
607     { "strict-nametypes", krb5_config_string, check_boolean, 0 },
608     { "svc-use-strongest-session-key", krb5_config_string, check_boolean, 0 },
609     { "tgt-use-strongest-session-key", krb5_config_string, check_boolean, 0 },
610     { "transited-policy", krb5_config_string, NULL, 0 },
611     { "use_2b", krb5_config_list, NULL, 0 },
612     { "use-strongest-server-key", krb5_config_string, check_boolean, 0 },
613     { "v4_realm", krb5_config_string, NULL, 0 },
614     { NULL, 0, NULL, 0 }
615 };
616
617 struct entry kadmin_entries[] = {
618     { "allow_self_change_password", krb5_config_string, check_boolean, 0 },
619     { "default_keys", krb5_config_string, NULL, 0 },
620     { "password_lifetime", krb5_config_string, check_time, 0 },
621     { "plugin_dir", krb5_config_string, check_directory, 0 },
622     { "require-preauth", krb5_config_string, check_boolean, 0 },
623     { "save-password", krb5_config_string, check_boolean, 0 },
624     { "use_v4_salt", krb5_config_string, NULL, 0 },
625     { NULL, 0, NULL, 0 }
626 };
627 struct entry log_strings[] = {
628     { "", krb5_config_string, check_log, 0 },
629     { NULL, 0, NULL, 0 }
630 };
631
632
633 /* MIT stuff */
634 struct entry kdcdefaults_entries[] = {
635     { "kdc_ports", krb5_config_string, mit_entry, 0 },
636     { "v4_mode", krb5_config_string, mit_entry, 0 },
637     { NULL, 0, NULL, 0 }
638 };
639
640 struct entry capaths_entries[] = {
641     { "", krb5_config_list, all_strings, 0 },
642     { NULL, 0, NULL, 0 }
643 };
644
645 struct entry kcm_entries[] = {
646     { "detach", krb5_config_string, check_boolean, 0 },
647     { "disallow-getting-krbtgt", krb5_config_string, check_boolean, 0 },
648     { "logging", krb5_config_string, NULL, 0 },
649     { "max-request", krb5_config_string, NULL, 0 },
650     { "system_ccache", krb5_config_string, NULL, 0 },
651     { NULL, 0, NULL, 0 }
652 };
653
654 struct entry password_quality_entries[] = {
655     { "enforce_on_admin_set", krb5_config_string, check_boolean, 0 },
656     { "check_function", krb5_config_string, NULL, 0 },
657     { "check_library", krb5_config_string, NULL, 0 },
658     { "external_program", krb5_config_string, NULL, 0 },
659     { "min_classes", krb5_config_string, check_numeric, 0 },
660     { "min_length", krb5_config_string, check_numeric, 0 },
661     { "policies", krb5_config_string, NULL, 0 },
662     { "policy_libraries", krb5_config_string, NULL, 0 },
663     { "", krb5_config_list, all_strings, 0 },
664     { NULL, 0, NULL, 0 }
665 };
666
667 struct entry toplevel_sections[] = {
668     { "appdefaults", krb5_config_list, appdefaults_entries, 0 },
669     { "capaths", krb5_config_list, capaths_entries, 0 },
670     { "domain_realm", krb5_config_list, all_strings, 0 },
671     { "gssapi", krb5_config_list, NULL, 0 },
672     { "kadmin", krb5_config_list, kadmin_entries, 0 },
673     { "kcm", krb5_config_list, kcm_entries, 0 },
674     { "kdc", krb5_config_list, kdc_entries, 0 },
675     { "libdefaults" , krb5_config_list, libdefaults_entries, 0 },
676     { "logging", krb5_config_list, log_strings, 0 },
677     { "password_quality", krb5_config_list, password_quality_entries, 0 },
678     { "realms", krb5_config_list, realms_foobar, 0 },
679
680     /* MIT stuff */
681     { "kdcdefaults", krb5_config_list, kdcdefaults_entries, 0 },
682     { NULL, 0, NULL, 0 }
683 };
684
685
686 static int
687 check_section(krb5_context context, const char *path, krb5_config_section *cf,
688               struct entry *entries)
689 {
690     int error = 0;
691     krb5_config_section *p;
692     struct entry *e;
693
694     char *local;
695
696     for(p = cf; p != NULL; p = p->next) {
697         local = NULL;
698         if (asprintf(&local, "%s/%s", path, p->name) < 0 || local == NULL)
699             errx(1, "out of memory");
700         for(e = entries; e->name != NULL; e++) {
701             if(*e->name == '\0' || strcmp(e->name, p->name) == 0) {
702                 if(e->type != p->type) {
703                     krb5_warnx(context, "%s: unknown or wrong type", local);
704                     error |= 1;
705                 } else if(p->type == krb5_config_string && e->check_data != NULL) {
706                     error |= (*(check_func_t)e->check_data)(context, local, p->u.string);
707                 } else if(p->type == krb5_config_list && e->check_data != NULL) {
708                     error |= check_section(context, local, p->u.list, e->check_data);
709                 }
710                 if(e->deprecated) {
711                     krb5_warnx(context, "%s: is a deprecated entry", local);
712                     error |= 1;
713                 }
714                 break;
715             }
716         }
717         if(e->name == NULL) {
718             krb5_warnx(context, "%s: unknown entry", local);
719             error |= 1;
720         }
721         free(local);
722     }
723     return error;
724 }
725
726
727 static void
728 dumpconfig(int level, krb5_config_section *top)
729 {
730     krb5_config_section *x;
731     for(x = top; x; x = x->next) {
732         switch(x->type) {
733         case krb5_config_list:
734             if(level == 0) {
735                 printf("[%s]\n", x->name);
736             } else {
737                 printf("%*s%s = {\n", 4 * level, " ", x->name);
738             }
739             dumpconfig(level + 1, x->u.list);
740             if(level > 0)
741                 printf("%*s}\n", 4 * level, " ");
742             break;
743         case krb5_config_string:
744             printf("%*s%s = %s\n", 4 * level, " ", x->name, x->u.string);
745             break;
746         }
747     }
748 }
749
750 int
751 main(int argc, char **argv)
752 {
753     krb5_context context;
754     krb5_error_code ret;
755     krb5_config_section *tmp_cf;
756     int optidx = 0;
757
758     setprogname (argv[0]);
759
760     ret = krb5_init_context(&context);
761     if (ret == KRB5_CONFIG_BADFORMAT)
762         errx (1, "krb5_init_context failed to parse configuration file");
763     else if (ret)
764         errx (1, "krb5_init_context failed with %d", ret);
765
766     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
767         usage(1);
768
769     if (help_flag)
770         usage (0);
771
772     if(version_flag){
773         print_version(NULL);
774         exit(0);
775     }
776
777     argc -= optidx;
778     argv += optidx;
779
780     tmp_cf = NULL;
781     if(argc == 0)
782         krb5_get_default_config_files(&argv);
783
784     while(*argv) {
785         ret = krb5_config_parse_file_multi(context, *argv, &tmp_cf);
786         if (ret != 0)
787             krb5_warn (context, ret, "krb5_config_parse_file");
788         argv++;
789     }
790
791     if(dumpconfig_flag)
792         dumpconfig(0, tmp_cf);
793
794     return check_section(context, "", tmp_cf, toplevel_sections);
795 }