From fd07afcd82939532c0f3110b72ce047e60257677 Mon Sep 17 00:00:00 2001 From: Johan Danielsson Date: Thu, 30 Aug 2001 18:57:39 +0000 Subject: [PATCH] do some checks of the values in the file git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@10605 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/krb5/verify_krb5_conf.8 | 48 +++++-- lib/krb5/verify_krb5_conf.c | 268 +++++++++++++++++++++++++++++++++++- 2 files changed, 303 insertions(+), 13 deletions(-) diff --git a/lib/krb5/verify_krb5_conf.8 b/lib/krb5/verify_krb5_conf.8 index aa15fe702..d5f633ce1 100644 --- a/lib/krb5/verify_krb5_conf.8 +++ b/lib/krb5/verify_krb5_conf.8 @@ -1,13 +1,11 @@ .\" $Id$ .\" -.Dd March 4, 2000 +.Dd August 30, 2001 .Dt VERIFY_KRB5_CONF 8 .Os HEIMDAL .Sh NAME .Nm verify_krb5_conf -.Nd does a crude test that -.Pa krb5.conf -does not contain any obvious syntax error +.Nd checks krb5.conf for obvious errors .Sh SYNOPSIS .Nm .Ar [config-file] @@ -17,9 +15,34 @@ reads the configuration file .Pa krb5.conf , or the file given on the command line, and parses it, thereby verifying that the syntax is not correctly wrong. -Since that file is read by almost all Kerberos programs but most of -them have no way of notifying the user that it could not be parsed, -this program is useful. +.Pp +If the file is syntactically correct, +.Nm +tries to verify that the contents of the file is of relevant nature. +.Sh DIAGNOSTICS +Possible output from +.Nm +include: + +.Bl -tag -width "" +.It ": failed to parse as size/time/number/boolean" +Usually means that is misspelled, or that it contains +weird characters. The parsing done by +.Nm +is more strict than the one performed by libkrb5, and so strings that +work in real life, might be reported as bad. +.It ": host not found ()" +Means that is supposed to point to a host, but it can't be +recognised as one. +.It : unknown or wrong type +Means that is either is a string when it should be a list, vice +versa, or just that +.Nm +is confused. +.It : unknown entry +Means that is not known by +.Nm "" . +.El .Sh ENVIRONMENT .Ev KRB5_CONFIG points to the configuration file to read. @@ -28,5 +51,12 @@ points to the configuration file to read. .Sh SEE ALSO .Xr krb5.conf 5 .Sh BUGS -It should know about what variables are actually used and warn about -unknown ones. +Since each application can put almost anything in the config file, +it's hard to come up with a water tight verification process. Most of +the default settings are sanity checked, but this does not mean that +every problem is discovered, or that everything that is reported as a +possible problem actually is one. This tool should thus be used with +some care. +.Pp +It should warn about obsolete data, or bad practice, but currently +doesn't. diff --git a/lib/krb5/verify_krb5_conf.c b/lib/krb5/verify_krb5_conf.c index cea94be17..b656a860e 100644 --- a/lib/krb5/verify_krb5_conf.c +++ b/lib/krb5/verify_krb5_conf.c @@ -33,6 +33,7 @@ #include "krb5_locl.h" #include +#include RCSID("$Id$"); /* verify krb5.conf */ @@ -57,6 +58,263 @@ usage (int ret) exit (ret); } +static int +check_bytes(krb5_context context, const char *path, char *data) +{ + if(parse_bytes(data, NULL) == -1) { + krb5_warnx(context, "%s: failed to parse \"%s\" as size", path, data); + return 1; + } + return 0; +} + +static int +check_time(krb5_context context, const char *path, char *data) +{ + if(parse_time(data, NULL) == -1) { + krb5_warnx(context, "%s: failed to parse \"%s\" as time", path, data); + return 1; + } + return 0; +} + +static int +check_numeric(krb5_context context, const char *path, char *data) +{ + long int v; + char *end; + v = strtol(data, &end, 0); + if(*end != '\0') { + krb5_warnx(context, "%s: failed to parse \"%s\" as a number", + path, data); + return 1; + } + return 0; +} + +static int +check_boolean(krb5_context context, const char *path, char *data) +{ + long int v; + char *end; + if(strcasecmp(data, "yes") == 0 || + strcasecmp(data, "true") == 0 || + strcasecmp(data, "no") == 0 || + strcasecmp(data, "false") == 0) + return 0; + v = strtol(data, &end, 0); + if(*end != '\0') { + krb5_warnx(context, "%s: failed to parse \"%s\" as a boolean", + path, data); + return 1; + } + return 0; +} + +static int +check_host(krb5_context context, const char *path, char *data) +{ + int ret; + char hostname[128]; + const char *p = data; + struct addrinfo *ai; + /* XXX data could be a list of hosts that this code can't handle */ + /* XXX copied from krbhst.c */ + if(strncmp(p, "http://", 7) == 0){ + p += 7; + } else if(strncmp(p, "http/", 5) == 0) { + p += 5; + }else if(strncmp(p, "tcp/", 4) == 0){ + p += 4; + } else if(strncmp(p, "udp/", 4) == 0) { + p += 4; + } + if(strsep_copy(&p, ":", hostname, sizeof(hostname)) < 0) { + return 1; + } + hostname[strcspn(hostname, "/")] = '\0'; + ret = getaddrinfo(hostname, "telnet" /* XXX */, NULL, &ai); + if(ret != 0) { + if(ret == EAI_NODATA) + krb5_warnx(context, "%s: host not found (%s)", path, hostname); + else + krb5_warnx(context, "%s: %s (%s)", path, gai_strerror(ret), hostname); + return 1; + } + return 0; +} + +typedef int (*check_func_t)(krb5_context, const char*, char*); +struct entry { + const char *name; + int type; + void *check_data; +}; + +struct entry all_strings[] = { + { "", krb5_config_string, NULL }, + { NULL } +}; + +struct entry v4_name_convert_entries[] = { + { "host", krb5_config_list, all_strings }, + { "plain", krb5_config_list, all_strings }, + { NULL } +}; + +struct entry libdefaults_entries[] = { + { "accept_null_addresses", krb5_config_string, check_boolean }, + { "capath", krb5_config_list, all_strings }, + { "clockskew", krb5_config_string, check_time }, + { "date_format", krb5_config_string, NULL }, + { "default_etypes", krb5_config_string, NULL }, + { "default_etypes_des", krb5_config_string, NULL }, + { "default_keytab_modify_name", krb5_config_string, NULL }, + { "default_keytab_name", krb5_config_string, NULL }, + { "default_realm", krb5_config_string, NULL }, + { "dns_proxy", krb5_config_string, NULL }, + { "egd_socket", krb5_config_string, NULL }, + { "encrypt", krb5_config_string, check_boolean }, + { "extra_addresses", krb5_config_string, NULL }, + { "fcache_version", krb5_config_string, check_numeric }, + { "forward", krb5_config_string, check_boolean }, + { "forwardable", krb5_config_string, check_boolean }, + { "http_proxy", krb5_config_string, check_host /* XXX */ }, + { "ignore_addresses", krb5_config_string, NULL }, + { "kdc_timeout", krb5_config_string, check_time }, + { "kdc_timesync", krb5_config_string, check_boolean }, + { "krb4_get_tickets", krb5_config_string, check_boolean }, + { "log_utc", krb5_config_string, check_boolean }, + { "maxretries", krb5_config_string, check_numeric }, + { "scan_interfaces", krb5_config_string, check_boolean }, + { "srv_lookup", krb5_config_string, check_boolean }, + { "srv_try_txt", krb5_config_string, check_boolean }, + { "ticket_lifetime", krb5_config_string, check_time }, + { "time_format", krb5_config_string, NULL }, + { "transited_realms_reject", krb5_config_string, NULL }, + { "v4_instance_resolve", krb5_config_string, check_boolean }, + { "v4_name_convert", krb5_config_list, v4_name_convert_entries }, + { "verify_ap_req_nofail", krb5_config_string, check_boolean }, + { NULL } +}; + +struct entry appdefaults_entries[] = { + { "forwardable", krb5_config_string, check_boolean }, + { "proxiable", krb5_config_string, check_boolean }, + { "ticket_lifetime", krb5_config_string, check_time }, + { "renew_lifetime", krb5_config_string, check_time }, + { "no-addresses", krb5_config_string, check_boolean }, +#if 0 + { "anonymous", krb5_config_string, check_boolean }, +#endif + { "", krb5_config_list, appdefaults_entries }, + { NULL } +}; + +struct entry realms_entries[] = { + { "forwardable", krb5_config_string, check_boolean }, + { "proxiable", krb5_config_string, check_boolean }, + { "ticket_lifetime", krb5_config_string, check_time }, + { "renew_lifetime", krb5_config_string, check_time }, + { "warn_pwexpire", krb5_config_string, check_time }, + { "kdc", krb5_config_string, check_host }, + { "admin_server", krb5_config_string, check_host }, + { "kpasswd_server", krb5_config_string, check_host }, + { "krb524_server", krb5_config_string, check_host }, + { "v4_name_convert", krb5_config_list, v4_name_convert_entries }, + { "v4_instance_convert", krb5_config_list, all_strings }, + { "v4_domains", krb5_config_string, NULL }, + { "default_domain", krb5_config_string, NULL }, + { NULL } +}; + +struct entry realms_foobar[] = { + { "", krb5_config_list, realms_entries }, + { NULL } +}; + + +struct entry kdc_database_entries[] = { + { "realm", krb5_config_string, NULL }, + { "dbname", krb5_config_string, NULL }, + { "mkey_file", krb5_config_string, NULL }, + { NULL } +}; + +struct entry kdc_entries[] = { + { "database", krb5_config_list, kdc_database_entries }, + { "key-file", krb5_config_string, NULL }, + { "logging", krb5_config_string, NULL }, + { "max-request", krb5_config_string, check_bytes }, + { "require-preauth", krb5_config_string, check_boolean }, + { "ports", krb5_config_string, NULL }, + { "addresses", krb5_config_string, NULL }, + { "enable-kerberos4", krb5_config_string, check_boolean }, + { "enable-524", krb5_config_string, check_boolean }, + { "enable-http", krb5_config_string, check_boolean }, + { "check_ticket-addresses", krb5_config_string, check_boolean }, + { "allow-null-addresses", krb5_config_string, check_boolean }, + { "allow-anonymous", krb5_config_string, check_boolean }, + { "v4_realm", krb5_config_string, NULL }, + { "enable-kaserver", krb5_config_string, check_boolean }, + { "encode_as_rep_as_tgs_rep", krb5_config_string, check_boolean }, + { "kdc_warn_pwexpire", krb5_config_string, check_time }, + { NULL } +}; + +struct entry kadmin_entries[] = { + { "password_lifetime", krb5_config_string, check_time }, + { "default_keys", krb5_config_string, NULL }, + { "use_v4_salt", krb5_config_string, NULL }, + { NULL } +}; +struct entry toplevel_sections[] = { + { "libdefaults" , krb5_config_list, libdefaults_entries }, + { "realms", krb5_config_list, realms_foobar }, + { "domain_realm", krb5_config_list, all_strings }, + { "logging", krb5_config_list, all_strings }, + { "kdc", krb5_config_list, kdc_entries }, + { "kadmin", krb5_config_list, kadmin_entries }, + { "appdefaults", krb5_config_list, appdefaults_entries }, + { NULL } +}; + + +static int +check_section(krb5_context context, const char *path, krb5_config_section *cf, + struct entry *entries) +{ + int error = 0; + krb5_config_section *p; + struct entry *e; + + char *local; + + for(p = cf; p != NULL; p = p->next) { + asprintf(&local, "%s/%s", path, p->name); + for(e = entries; e->name != NULL; e++) { + if(*e->name == '\0' || strcmp(e->name, p->name) == 0) { + if(e->type != p->type) { + krb5_warnx(context, "%s: unknown or wrong type", local); + error |= 1; + } else if(p->type == krb5_config_string && e->check_data != NULL) { + error |= (*(check_func_t)e->check_data)(context, local, p->u.string); + } else if(p->type == krb5_config_list && e->check_data != NULL) { + error |= check_section(context, local, p->u.list, e->check_data); + } + break; + } + } + if(e->name == NULL) { + krb5_warnx(context, "%s: unknown entry", local); + error |= 1; + } + free(local); + } + return error; +} + + int main(int argc, char **argv) { @@ -97,8 +355,10 @@ main(int argc, char **argv) } ret = krb5_config_parse_file (context, config_file, &tmp_cf); - if (ret == 0) - return 0; - krb5_warn (context, ret, "krb5_config_parse_file"); - return 1; + if (ret != 0) { + krb5_warn (context, ret, "krb5_config_parse_file"); + return 1; + } + + return check_section(context, "", tmp_cf, toplevel_sections); }