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