1 /* 2 * Copyright (c) 1999 - 2002 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 RCSID("$Id: verify_krb5_conf.c,v 1.14 2002/08/28 15:27:19 nectar Exp $"); 39 40 /* verify krb5.conf */ 41 42 static int dumpconfig_flag = 0; 43 static int version_flag = 0; 44 static int help_flag = 0; 45 46 static struct getargs args[] = { 47 {"dumpconfig", 0, arg_flag, &dumpconfig_flag, 48 "show the parsed config files", NULL }, 49 {"version", 0, arg_flag, &version_flag, 50 "print version", NULL }, 51 {"help", 0, arg_flag, &help_flag, 52 NULL, NULL } 53 }; 54 55 static void 56 usage (int ret) 57 { 58 arg_printusage (args, 59 sizeof(args)/sizeof(*args), 60 NULL, 61 "[config-file]"); 62 exit (ret); 63 } 64 65 static int 66 check_bytes(krb5_context context, const char *path, char *data) 67 { 68 if(parse_bytes(data, NULL) == -1) { 69 krb5_warnx(context, "%s: failed to parse \"%s\" as size", path, data); 70 return 1; 71 } 72 return 0; 73 } 74 75 static int 76 check_time(krb5_context context, const char *path, char *data) 77 { 78 if(parse_time(data, NULL) == -1) { 79 krb5_warnx(context, "%s: failed to parse \"%s\" as time", path, data); 80 return 1; 81 } 82 return 0; 83 } 84 85 static int 86 check_numeric(krb5_context context, const char *path, char *data) 87 { 88 long int v; 89 char *end; 90 v = strtol(data, &end, 0); 91 if(*end != '\0') { 92 krb5_warnx(context, "%s: failed to parse \"%s\" as a number", 93 path, data); 94 return 1; 95 } 96 return 0; 97 } 98 99 static int 100 check_boolean(krb5_context context, const char *path, char *data) 101 { 102 long int v; 103 char *end; 104 if(strcasecmp(data, "yes") == 0 || 105 strcasecmp(data, "true") == 0 || 106 strcasecmp(data, "no") == 0 || 107 strcasecmp(data, "false") == 0) 108 return 0; 109 v = strtol(data, &end, 0); 110 if(*end != '\0') { 111 krb5_warnx(context, "%s: failed to parse \"%s\" as a boolean", 112 path, data); 113 return 1; 114 } 115 if(v != 0 && v != 1) 116 krb5_warnx(context, "%s: numeric value \"%s\" is treated as \"true\"", 117 path, data); 118 return 0; 119 } 120 121 static int 122 check_host(krb5_context context, const char *path, char *data) 123 { 124 int ret; 125 char hostname[128]; 126 const char *p = data; 127 struct addrinfo *ai; 128 /* XXX data could be a list of hosts that this code can't handle */ 129 /* XXX copied from krbhst.c */ 130 if(strncmp(p, "http://", 7) == 0){ 131 p += 7; 132 } else if(strncmp(p, "http/", 5) == 0) { 133 p += 5; 134 }else if(strncmp(p, "tcp/", 4) == 0){ 135 p += 4; 136 } else if(strncmp(p, "udp/", 4) == 0) { 137 p += 4; 138 } 139 if(strsep_copy(&p, ":", hostname, sizeof(hostname)) < 0) { 140 return 1; 141 } 142 hostname[strcspn(hostname, "/")] = '\0'; 143 ret = getaddrinfo(hostname, "telnet" /* XXX */, NULL, &ai); 144 if(ret != 0) { 145 if(ret == EAI_NODATA) 146 krb5_warnx(context, "%s: host not found (%s)", path, hostname); 147 else 148 krb5_warnx(context, "%s: %s (%s)", path, gai_strerror(ret), hostname); 149 return 1; 150 } 151 return 0; 152 } 153 154 #if 0 155 static int 156 mit_entry(krb5_context context, const char *path, char *data) 157 { 158 krb5_warnx(context, "%s is only used by MIT Kerberos", path); 159 return 0; 160 } 161 #endif 162 163 struct s2i { 164 char *s; 165 int val; 166 }; 167 168 #define L(X) { #X, LOG_ ## X } 169 170 static struct s2i syslogvals[] = { 171 L(EMERG), 172 L(ALERT), 173 L(CRIT), 174 L(ERR), 175 L(WARNING), 176 L(NOTICE), 177 L(INFO), 178 L(DEBUG), 179 180 L(AUTH), 181 #ifdef LOG_AUTHPRIV 182 L(AUTHPRIV), 183 #endif 184 #ifdef LOG_CRON 185 L(CRON), 186 #endif 187 L(DAEMON), 188 #ifdef LOG_FTP 189 L(FTP), 190 #endif 191 L(KERN), 192 L(LPR), 193 L(MAIL), 194 #ifdef LOG_NEWS 195 L(NEWS), 196 #endif 197 L(SYSLOG), 198 L(USER), 199 #ifdef LOG_UUCP 200 L(UUCP), 201 #endif 202 L(LOCAL0), 203 L(LOCAL1), 204 L(LOCAL2), 205 L(LOCAL3), 206 L(LOCAL4), 207 L(LOCAL5), 208 L(LOCAL6), 209 L(LOCAL7), 210 { NULL, -1 } 211 }; 212 213 static int 214 find_value(const char *s, struct s2i *table) 215 { 216 while(table->s && strcasecmp(table->s, s)) 217 table++; 218 return table->val; 219 } 220 221 static int 222 check_log(krb5_context context, const char *path, char *data) 223 { 224 /* XXX sync with log.c */ 225 int min = 0, max = -1, n; 226 char c; 227 const char *p = data; 228 229 n = sscanf(p, "%d%c%d/", &min, &c, &max); 230 if(n == 2){ 231 if(c == '/') { 232 if(min < 0){ 233 max = -min; 234 min = 0; 235 }else{ 236 max = min; 237 } 238 } 239 } 240 if(n){ 241 p = strchr(p, '/'); 242 if(p == NULL) { 243 krb5_warnx(context, "%s: failed to parse \"%s\"", path, data); 244 return 1; 245 } 246 p++; 247 } 248 if(strcmp(p, "STDERR") == 0 || 249 strcmp(p, "CONSOLE") == 0 || 250 (strncmp(p, "FILE", 4) == 0 && (p[4] == ':' || p[4] == '=')) || 251 (strncmp(p, "DEVICE", 6) == 0 && p[6] == '=')) 252 return 0; 253 if(strncmp(p, "SYSLOG", 6) == 0){ 254 int ret = 0; 255 char severity[128] = ""; 256 char facility[128] = ""; 257 p += 6; 258 if(*p != '\0') 259 p++; 260 if(strsep_copy(&p, ":", severity, sizeof(severity)) != -1) 261 strsep_copy(&p, ":", facility, sizeof(facility)); 262 if(*severity == '\0') 263 strlcpy(severity, "ERR", sizeof(severity)); 264 if(*facility == '\0') 265 strlcpy(facility, "AUTH", sizeof(facility)); 266 if(find_value(severity, syslogvals) == NULL) { 267 krb5_warnx(context, "%s: unknown syslog facility \"%s\"", 268 path, facility); 269 ret++; 270 } 271 if(find_value(severity, syslogvals) == NULL) { 272 krb5_warnx(context, "%s: unknown syslog severity \"%s\"", 273 path, severity); 274 ret++; 275 } 276 return ret; 277 }else{ 278 krb5_warnx(context, "%s: unknown log type: \"%s\"", path, data); 279 return 1; 280 } 281 } 282 283 typedef int (*check_func_t)(krb5_context, const char*, char*); 284 struct entry { 285 const char *name; 286 int type; 287 void *check_data; 288 }; 289 290 struct entry all_strings[] = { 291 { "", krb5_config_string, NULL }, 292 { NULL } 293 }; 294 295 struct entry v4_name_convert_entries[] = { 296 { "host", krb5_config_list, all_strings }, 297 { "plain", krb5_config_list, all_strings }, 298 { NULL } 299 }; 300 301 struct entry libdefaults_entries[] = { 302 { "accept_null_addresses", krb5_config_string, check_boolean }, 303 { "capath", krb5_config_list, all_strings }, 304 { "clockskew", krb5_config_string, check_time }, 305 { "date_format", krb5_config_string, NULL }, 306 { "default_etypes", krb5_config_string, NULL }, 307 { "default_etypes_des", krb5_config_string, NULL }, 308 { "default_keytab_modify_name", krb5_config_string, NULL }, 309 { "default_keytab_name", krb5_config_string, NULL }, 310 { "default_realm", krb5_config_string, NULL }, 311 { "dns_proxy", krb5_config_string, NULL }, 312 { "dns_lookup_kdc", krb5_config_string, check_boolean }, 313 { "dns_lookup_realm", krb5_config_string, check_boolean }, 314 { "dns_lookup_realm_labels", krb5_config_string, NULL }, 315 { "egd_socket", krb5_config_string, NULL }, 316 { "encrypt", krb5_config_string, check_boolean }, 317 { "extra_addresses", krb5_config_string, NULL }, 318 { "fcache_version", krb5_config_string, check_numeric }, 319 { "forward", krb5_config_string, check_boolean }, 320 { "forwardable", krb5_config_string, check_boolean }, 321 { "http_proxy", krb5_config_string, check_host /* XXX */ }, 322 { "ignore_addresses", krb5_config_string, NULL }, 323 { "kdc_timeout", krb5_config_string, check_time }, 324 { "kdc_timesync", krb5_config_string, check_boolean }, 325 { "log_utc", krb5_config_string, check_boolean }, 326 { "maxretries", krb5_config_string, check_numeric }, 327 { "scan_interfaces", krb5_config_string, check_boolean }, 328 { "srv_lookup", krb5_config_string, check_boolean }, 329 { "srv_try_txt", krb5_config_string, check_boolean }, 330 { "ticket_lifetime", krb5_config_string, check_time }, 331 { "time_format", krb5_config_string, NULL }, 332 { "transited_realms_reject", krb5_config_string, NULL }, 333 { "v4_instance_resolve", krb5_config_string, check_boolean }, 334 { "v4_name_convert", krb5_config_list, v4_name_convert_entries }, 335 { "verify_ap_req_nofail", krb5_config_string, check_boolean }, 336 { NULL } 337 }; 338 339 struct entry appdefaults_entries[] = { 340 { "forwardable", krb5_config_string, check_boolean }, 341 { "proxiable", krb5_config_string, check_boolean }, 342 { "ticket_lifetime", krb5_config_string, check_time }, 343 { "renew_lifetime", krb5_config_string, check_time }, 344 { "no-addresses", krb5_config_string, check_boolean }, 345 { "krb4_get_tickets", krb5_config_string, check_boolean }, 346 #if 0 347 { "anonymous", krb5_config_string, check_boolean }, 348 #endif 349 { "", krb5_config_list, appdefaults_entries }, 350 { NULL } 351 }; 352 353 struct entry realms_entries[] = { 354 { "forwardable", krb5_config_string, check_boolean }, 355 { "proxiable", krb5_config_string, check_boolean }, 356 { "ticket_lifetime", krb5_config_string, check_time }, 357 { "renew_lifetime", krb5_config_string, check_time }, 358 { "warn_pwexpire", krb5_config_string, check_time }, 359 { "kdc", krb5_config_string, check_host }, 360 { "admin_server", krb5_config_string, check_host }, 361 { "kpasswd_server", krb5_config_string, check_host }, 362 { "krb524_server", krb5_config_string, check_host }, 363 { "v4_name_convert", krb5_config_list, v4_name_convert_entries }, 364 { "v4_instance_convert", krb5_config_list, all_strings }, 365 { "v4_domains", krb5_config_string, NULL }, 366 { "default_domain", krb5_config_string, NULL }, 367 #if 0 368 /* MIT stuff */ 369 { "admin_keytab", krb5_config_string, mit_entry }, 370 { "acl_file", krb5_config_string, mit_entry }, 371 { "dict_file", krb5_config_string, mit_entry }, 372 { "kadmind_port", krb5_config_string, mit_entry }, 373 { "kpasswd_port", krb5_config_string, mit_entry }, 374 { "master_key_name", krb5_config_string, mit_entry }, 375 { "master_key_type", krb5_config_string, mit_entry }, 376 { "key_stash_file", krb5_config_string, mit_entry }, 377 { "max_life", krb5_config_string, mit_entry }, 378 { "max_renewable_life", krb5_config_string, mit_entry }, 379 { "default_principal_expiration", krb5_config_string, mit_entry }, 380 { "default_principal_flags", krb5_config_string, mit_entry }, 381 { "supported_enctypes", krb5_config_string, mit_entry }, 382 { "database_name", krb5_config_string, mit_entry }, 383 #endif 384 { NULL } 385 }; 386 387 struct entry realms_foobar[] = { 388 { "", krb5_config_list, realms_entries }, 389 { NULL } 390 }; 391 392 393 struct entry kdc_database_entries[] = { 394 { "realm", krb5_config_string, NULL }, 395 { "dbname", krb5_config_string, NULL }, 396 { "mkey_file", krb5_config_string, NULL }, 397 { NULL } 398 }; 399 400 struct entry kdc_entries[] = { 401 { "database", krb5_config_list, kdc_database_entries }, 402 { "key-file", krb5_config_string, NULL }, 403 { "logging", krb5_config_string, check_log }, 404 { "max-request", krb5_config_string, check_bytes }, 405 { "require-preauth", krb5_config_string, check_boolean }, 406 { "ports", krb5_config_string, NULL }, 407 { "addresses", krb5_config_string, NULL }, 408 { "enable-kerberos4", krb5_config_string, check_boolean }, 409 { "enable-524", krb5_config_string, check_boolean }, 410 { "enable-http", krb5_config_string, check_boolean }, 411 { "check_ticket-addresses", krb5_config_string, check_boolean }, 412 { "allow-null-addresses", krb5_config_string, check_boolean }, 413 { "allow-anonymous", krb5_config_string, check_boolean }, 414 { "v4_realm", krb5_config_string, NULL }, 415 { "enable-kaserver", krb5_config_string, check_boolean }, 416 { "encode_as_rep_as_tgs_rep", krb5_config_string, check_boolean }, 417 { "kdc_warn_pwexpire", krb5_config_string, check_time }, 418 { NULL } 419 }; 420 421 struct entry kadmin_entries[] = { 422 { "password_lifetime", krb5_config_string, check_time }, 423 { "default_keys", krb5_config_string, NULL }, 424 { "use_v4_salt", krb5_config_string, NULL }, 425 { NULL } 426 }; 427 struct entry log_strings[] = { 428 { "", krb5_config_string, check_log }, 429 { NULL } 430 }; 431 432 433 #if 0 434 struct entry kdcdefaults_entries[] = { 435 { "kdc_ports, krb5_config_string, mit_entry }, 436 { "v4_mode, krb5_config_string, mit_entry }, 437 { NULL } 438 }; 439 #endif 440 441 struct entry toplevel_sections[] = { 442 { "libdefaults" , krb5_config_list, libdefaults_entries }, 443 { "realms", krb5_config_list, realms_foobar }, 444 { "domain_realm", krb5_config_list, all_strings }, 445 { "logging", krb5_config_list, log_strings }, 446 { "kdc", krb5_config_list, kdc_entries }, 447 { "kadmin", krb5_config_list, kadmin_entries }, 448 { "appdefaults", krb5_config_list, appdefaults_entries }, 449 #if 0 450 /* MIT stuff */ 451 { "kdcdefaults", krb5_config_list, kdcdefaults_entries }, 452 #endif 453 { NULL } 454 }; 455 456 457 static int 458 check_section(krb5_context context, const char *path, krb5_config_section *cf, 459 struct entry *entries) 460 { 461 int error = 0; 462 krb5_config_section *p; 463 struct entry *e; 464 465 char *local; 466 467 for(p = cf; p != NULL; p = p->next) { 468 asprintf(&local, "%s/%s", path, p->name); 469 for(e = entries; e->name != NULL; e++) { 470 if(*e->name == '\0' || strcmp(e->name, p->name) == 0) { 471 if(e->type != p->type) { 472 krb5_warnx(context, "%s: unknown or wrong type", local); 473 error |= 1; 474 } else if(p->type == krb5_config_string && e->check_data != NULL) { 475 error |= (*(check_func_t)e->check_data)(context, local, p->u.string); 476 } else if(p->type == krb5_config_list && e->check_data != NULL) { 477 error |= check_section(context, local, p->u.list, e->check_data); 478 } 479 break; 480 } 481 } 482 if(e->name == NULL) { 483 krb5_warnx(context, "%s: unknown entry", local); 484 for(e = entries; e->name != NULL; e++) 485 krb5_warnx(context, " %s", e->name); 486 error |= 1; 487 } 488 free(local); 489 } 490 return error; 491 } 492 493 494 static void 495 dumpconfig(int level, krb5_config_section *top) 496 { 497 krb5_config_section *x; 498 for(x = top; x; x = x->next) { 499 switch(x->type) { 500 case krb5_config_list: 501 if(level == 0) { 502 printf("[%s]\n", x->name); 503 } else { 504 printf("%*s%s = {\n", 4 * level, " ", x->name); 505 } 506 dumpconfig(level + 1, x->u.list); 507 if(level > 0) 508 printf("%*s}\n", 4 * level, " "); 509 break; 510 case krb5_config_string: 511 printf("%*s%s = %s\n", 4 * level, " ", x->name, x->u.string); 512 break; 513 } 514 } 515 } 516 517 int 518 main(int argc, char **argv) 519 { 520 krb5_context context; 521 krb5_error_code ret; 522 krb5_config_section *tmp_cf; 523 int optind = 0; 524 525 setprogname (argv[0]); 526 527 ret = krb5_init_context(&context); 528 if (ret) 529 errx (1, "krb5_init_context failed"); 530 531 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind)) 532 usage(1); 533 534 if (help_flag) 535 usage (0); 536 537 if(version_flag){ 538 print_version(NULL); 539 exit(0); 540 } 541 542 argc -= optind; 543 argv += optind; 544 545 tmp_cf = NULL; 546 if(argc == 0) 547 krb5_get_default_config_files(&argv); 548 549 while(*argv) { 550 ret = krb5_config_parse_file_multi(context, *argv, &tmp_cf); 551 if (ret != 0) 552 krb5_warn (context, ret, "krb5_config_parse_file"); 553 argv++; 554 } 555 556 if(dumpconfig_flag) 557 dumpconfig(0, tmp_cf); 558 559 return check_section(context, "", tmp_cf, toplevel_sections); 560 } 561