Home | History | Annotate | Line # | Download | only in dnssec
dnssectool.c revision 1.12
      1  1.11  christos /*	$NetBSD: dnssectool.c,v 1.12 2025/05/21 14:47:35 christos Exp $	*/
      2   1.1  christos 
      3   1.1  christos /*
      4   1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5   1.1  christos  *
      6   1.7  christos  * SPDX-License-Identifier: MPL-2.0
      7   1.7  christos  *
      8   1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      9   1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10   1.5  christos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11   1.1  christos  *
     12   1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     13   1.1  christos  * information regarding copyright ownership.
     14   1.1  christos  */
     15   1.1  christos 
     16   1.1  christos /*! \file */
     17   1.1  christos 
     18   1.1  christos /*%
     19   1.1  christos  * DNSSEC Support Routines.
     20   1.1  christos  */
     21   1.1  christos 
     22   1.3  christos #include <inttypes.h>
     23   1.3  christos #include <stdbool.h>
     24   1.1  christos #include <stdlib.h>
     25  1.10  christos #include <unistd.h>
     26   1.1  christos 
     27   1.1  christos #include <isc/base32.h>
     28   1.1  christos #include <isc/buffer.h>
     29   1.1  christos #include <isc/commandline.h>
     30   1.1  christos #include <isc/dir.h>
     31   1.1  christos #include <isc/file.h>
     32   1.1  christos #include <isc/heap.h>
     33   1.1  christos #include <isc/list.h>
     34   1.1  christos #include <isc/mem.h>
     35   1.9  christos #include <isc/result.h>
     36   1.1  christos #include <isc/string.h>
     37   1.1  christos #include <isc/time.h>
     38  1.11  christos #include <isc/tls.h>
     39   1.9  christos #include <isc/tm.h>
     40   1.1  christos #include <isc/util.h>
     41   1.1  christos 
     42   1.1  christos #include <dns/db.h>
     43   1.1  christos #include <dns/dbiterator.h>
     44   1.1  christos #include <dns/dnssec.h>
     45   1.1  christos #include <dns/fixedname.h>
     46  1.11  christos #include <dns/journal.h>
     47   1.1  christos #include <dns/keyvalues.h>
     48   1.1  christos #include <dns/log.h>
     49   1.1  christos #include <dns/name.h>
     50   1.1  christos #include <dns/nsec.h>
     51   1.1  christos #include <dns/nsec3.h>
     52   1.1  christos #include <dns/rdataclass.h>
     53   1.1  christos #include <dns/rdataset.h>
     54   1.1  christos #include <dns/rdatasetiter.h>
     55   1.4  christos #include <dns/rdatastruct.h>
     56   1.1  christos #include <dns/rdatatype.h>
     57   1.1  christos #include <dns/secalg.h>
     58   1.1  christos #include <dns/time.h>
     59   1.1  christos 
     60   1.1  christos #include "dnssectool.h"
     61   1.1  christos 
     62   1.4  christos #define KEYSTATES_NVALUES 4
     63   1.4  christos static const char *keystates[KEYSTATES_NVALUES] = {
     64   1.4  christos 	"hidden",
     65   1.4  christos 	"rumoured",
     66   1.4  christos 	"omnipresent",
     67   1.4  christos 	"unretentive",
     68   1.4  christos };
     69   1.4  christos 
     70   1.4  christos int verbose = 0;
     71   1.4  christos bool quiet = false;
     72  1.11  christos const char *journal = NULL;
     73   1.9  christos dns_dsdigest_t dtype[8];
     74   1.1  christos 
     75   1.1  christos static fatalcallback_t *fatalcallback = NULL;
     76   1.1  christos 
     77   1.1  christos void
     78   1.1  christos fatal(const char *format, ...) {
     79   1.1  christos 	va_list args;
     80   1.1  christos 
     81   1.1  christos 	fprintf(stderr, "%s: fatal: ", program);
     82   1.1  christos 	va_start(args, format);
     83   1.1  christos 	vfprintf(stderr, format, args);
     84   1.1  christos 	va_end(args);
     85   1.1  christos 	fprintf(stderr, "\n");
     86   1.4  christos 	if (fatalcallback != NULL) {
     87   1.1  christos 		(*fatalcallback)();
     88   1.4  christos 	}
     89  1.10  christos 	_exit(EXIT_FAILURE);
     90   1.1  christos }
     91   1.1  christos 
     92   1.1  christos void
     93   1.1  christos setfatalcallback(fatalcallback_t *callback) {
     94   1.1  christos 	fatalcallback = callback;
     95   1.1  christos }
     96   1.1  christos 
     97   1.1  christos void
     98   1.1  christos check_result(isc_result_t result, const char *message) {
     99   1.4  christos 	if (result != ISC_R_SUCCESS) {
    100   1.1  christos 		fatal("%s: %s", message, isc_result_totext(result));
    101   1.4  christos 	}
    102   1.1  christos }
    103   1.1  christos 
    104   1.1  christos void
    105   1.1  christos vbprintf(int level, const char *fmt, ...) {
    106   1.1  christos 	va_list ap;
    107   1.4  christos 	if (level > verbose) {
    108   1.1  christos 		return;
    109   1.4  christos 	}
    110   1.1  christos 	va_start(ap, fmt);
    111   1.1  christos 	fprintf(stderr, "%s: ", program);
    112   1.1  christos 	vfprintf(stderr, fmt, ap);
    113   1.1  christos 	va_end(ap);
    114   1.1  christos }
    115   1.1  christos 
    116   1.1  christos void
    117   1.1  christos version(const char *name) {
    118  1.11  christos 	printf("%s %s\n", name, PACKAGE_VERSION);
    119  1.10  christos 	exit(EXIT_SUCCESS);
    120   1.1  christos }
    121   1.1  christos 
    122   1.1  christos void
    123   1.1  christos sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size) {
    124   1.1  christos 	char namestr[DNS_NAME_FORMATSIZE];
    125   1.1  christos 	char algstr[DNS_NAME_FORMATSIZE];
    126   1.1  christos 
    127   1.1  christos 	dns_name_format(&sig->signer, namestr, sizeof(namestr));
    128   1.1  christos 	dns_secalg_format(sig->algorithm, algstr, sizeof(algstr));
    129   1.1  christos 	snprintf(cp, size, "%s/%s/%d", namestr, algstr, sig->keyid);
    130   1.1  christos }
    131   1.1  christos 
    132   1.1  christos void
    133   1.1  christos setup_logging(isc_mem_t *mctx, isc_log_t **logp) {
    134   1.1  christos 	isc_logdestination_t destination;
    135   1.1  christos 	isc_logconfig_t *logconfig = NULL;
    136   1.1  christos 	isc_log_t *log = NULL;
    137   1.1  christos 	int level;
    138   1.1  christos 
    139   1.4  christos 	if (verbose < 0) {
    140   1.1  christos 		verbose = 0;
    141   1.4  christos 	}
    142   1.1  christos 	switch (verbose) {
    143   1.1  christos 	case 0:
    144   1.1  christos 		/*
    145   1.1  christos 		 * We want to see warnings about things like out-of-zone
    146   1.1  christos 		 * data in the master file even when not verbose.
    147   1.1  christos 		 */
    148   1.1  christos 		level = ISC_LOG_WARNING;
    149   1.1  christos 		break;
    150   1.1  christos 	case 1:
    151   1.1  christos 		level = ISC_LOG_INFO;
    152   1.1  christos 		break;
    153   1.1  christos 	default:
    154   1.1  christos 		level = ISC_LOG_DEBUG(verbose - 2 + 1);
    155   1.1  christos 		break;
    156   1.1  christos 	}
    157   1.1  christos 
    158   1.4  christos 	isc_log_create(mctx, &log, &logconfig);
    159   1.1  christos 	isc_log_setcontext(log);
    160   1.1  christos 	dns_log_init(log);
    161   1.1  christos 	dns_log_setcontext(log);
    162   1.4  christos 	isc_log_settag(logconfig, program);
    163   1.1  christos 
    164   1.1  christos 	/*
    165   1.1  christos 	 * Set up a channel similar to default_stderr except:
    166   1.1  christos 	 *  - the logging level is passed in
    167   1.1  christos 	 *  - the program name and logging level are printed
    168   1.1  christos 	 *  - no time stamp is printed
    169   1.1  christos 	 */
    170   1.1  christos 	destination.file.stream = stderr;
    171   1.1  christos 	destination.file.name = NULL;
    172   1.1  christos 	destination.file.versions = ISC_LOG_ROLLNEVER;
    173   1.1  christos 	destination.file.maximum_size = 0;
    174   1.4  christos 	isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC, level,
    175   1.4  christos 			      &destination,
    176   1.4  christos 			      ISC_LOG_PRINTTAG | ISC_LOG_PRINTLEVEL);
    177   1.1  christos 
    178   1.4  christos 	RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL) ==
    179   1.4  christos 		      ISC_R_SUCCESS);
    180   1.1  christos 
    181   1.1  christos 	*logp = log;
    182   1.1  christos }
    183   1.1  christos 
    184   1.1  christos void
    185   1.1  christos cleanup_logging(isc_log_t **logp) {
    186   1.1  christos 	isc_log_t *log;
    187   1.1  christos 
    188   1.1  christos 	REQUIRE(logp != NULL);
    189   1.1  christos 
    190   1.1  christos 	log = *logp;
    191   1.1  christos 	*logp = NULL;
    192   1.1  christos 
    193   1.4  christos 	if (log == NULL) {
    194   1.1  christos 		return;
    195   1.4  christos 	}
    196   1.1  christos 
    197   1.1  christos 	isc_log_destroy(&log);
    198   1.1  christos 	isc_log_setcontext(NULL);
    199   1.1  christos 	dns_log_setcontext(NULL);
    200   1.1  christos }
    201   1.1  christos 
    202   1.1  christos static isc_stdtime_t
    203   1.1  christos time_units(isc_stdtime_t offset, char *suffix, const char *str) {
    204   1.1  christos 	switch (suffix[0]) {
    205   1.4  christos 	case 'Y':
    206   1.4  christos 	case 'y':
    207  1.11  christos 		return offset * (365 * 24 * 3600);
    208   1.4  christos 	case 'M':
    209   1.4  christos 	case 'm':
    210   1.1  christos 		switch (suffix[1]) {
    211   1.4  christos 		case 'O':
    212   1.4  christos 		case 'o':
    213  1.11  christos 			return offset * (30 * 24 * 3600);
    214   1.4  christos 		case 'I':
    215   1.4  christos 		case 'i':
    216  1.11  christos 			return offset * 60;
    217   1.4  christos 		case '\0':
    218   1.1  christos 			fatal("'%s' ambiguous: use 'mi' for minutes "
    219   1.4  christos 			      "or 'mo' for months",
    220   1.4  christos 			      str);
    221   1.4  christos 		default:
    222   1.1  christos 			fatal("time value %s is invalid", str);
    223   1.1  christos 		}
    224   1.7  christos 		UNREACHABLE();
    225   1.1  christos 		break;
    226   1.4  christos 	case 'W':
    227   1.4  christos 	case 'w':
    228  1.11  christos 		return offset * (7 * 24 * 3600);
    229   1.4  christos 	case 'D':
    230   1.4  christos 	case 'd':
    231  1.11  christos 		return offset * (24 * 3600);
    232   1.4  christos 	case 'H':
    233   1.4  christos 	case 'h':
    234  1.11  christos 		return offset * 3600;
    235   1.4  christos 	case 'S':
    236   1.4  christos 	case 's':
    237   1.4  christos 	case '\0':
    238  1.11  christos 		return offset;
    239   1.4  christos 	default:
    240   1.1  christos 		fatal("time value %s is invalid", str);
    241   1.1  christos 	}
    242   1.7  christos 	UNREACHABLE();
    243  1.11  christos 	return 0; /* silence compiler warning */
    244   1.1  christos }
    245   1.1  christos 
    246   1.7  christos static bool
    247   1.1  christos isnone(const char *str) {
    248  1.11  christos 	return (strcasecmp(str, "none") == 0) ||
    249  1.11  christos 	       (strcasecmp(str, "never") == 0) ||
    250  1.11  christos 	       (strcasecmp(str, "unset") == 0);
    251   1.1  christos }
    252   1.1  christos 
    253   1.1  christos dns_ttl_t
    254   1.1  christos strtottl(const char *str) {
    255   1.1  christos 	const char *orig = str;
    256   1.1  christos 	dns_ttl_t ttl;
    257   1.1  christos 	char *endp;
    258   1.1  christos 
    259   1.4  christos 	if (isnone(str)) {
    260  1.11  christos 		return (dns_ttl_t)0;
    261   1.4  christos 	}
    262   1.1  christos 
    263   1.1  christos 	ttl = strtol(str, &endp, 0);
    264   1.4  christos 	if (ttl == 0 && endp == str) {
    265   1.1  christos 		fatal("TTL must be numeric");
    266   1.4  christos 	}
    267   1.1  christos 	ttl = time_units(ttl, endp, orig);
    268  1.11  christos 	return ttl;
    269   1.1  christos }
    270   1.1  christos 
    271   1.4  christos dst_key_state_t
    272   1.4  christos strtokeystate(const char *str) {
    273   1.4  christos 	if (isnone(str)) {
    274  1.11  christos 		return DST_KEY_STATE_NA;
    275   1.4  christos 	}
    276   1.4  christos 
    277   1.4  christos 	for (int i = 0; i < KEYSTATES_NVALUES; i++) {
    278   1.4  christos 		if (keystates[i] != NULL && strcasecmp(str, keystates[i]) == 0)
    279   1.4  christos 		{
    280  1.11  christos 			return (dst_key_state_t)i;
    281   1.4  christos 		}
    282   1.4  christos 	}
    283   1.6  christos 	fatal("unknown key state %s", str);
    284   1.4  christos }
    285   1.4  christos 
    286   1.1  christos isc_stdtime_t
    287   1.4  christos strtotime(const char *str, int64_t now, int64_t base, bool *setp) {
    288   1.3  christos 	int64_t val, offset;
    289   1.1  christos 	isc_result_t result;
    290   1.1  christos 	const char *orig = str;
    291   1.1  christos 	char *endp;
    292   1.1  christos 	size_t n;
    293   1.9  christos 	struct tm tm;
    294   1.1  christos 
    295   1.1  christos 	if (isnone(str)) {
    296  1.11  christos 		SET_IF_NOT_NULL(setp, false);
    297  1.11  christos 		return (isc_stdtime_t)0;
    298   1.1  christos 	}
    299   1.1  christos 
    300  1.11  christos 	SET_IF_NOT_NULL(setp, true);
    301   1.1  christos 
    302   1.4  christos 	if ((str[0] == '0' || str[0] == '-') && str[1] == '\0') {
    303  1.11  christos 		return (isc_stdtime_t)0;
    304   1.4  christos 	}
    305   1.1  christos 
    306   1.1  christos 	/*
    307   1.1  christos 	 * We accept times in the following formats:
    308   1.1  christos 	 *   now([+-]offset)
    309   1.1  christos 	 *   YYYYMMDD([+-]offset)
    310   1.1  christos 	 *   YYYYMMDDhhmmss([+-]offset)
    311   1.9  christos 	 *   Day Mon DD HH:MM:SS YYYY([+-]offset)
    312   1.9  christos 	 *   1234567890([+-]offset)
    313   1.1  christos 	 *   [+-]offset
    314   1.1  christos 	 */
    315   1.1  christos 	n = strspn(str, "0123456789");
    316   1.1  christos 	if ((n == 8u || n == 14u) &&
    317   1.8  christos 	    (str[n] == '\0' || str[n] == '-' || str[n] == '+'))
    318   1.8  christos 	{
    319   1.1  christos 		char timestr[15];
    320   1.1  christos 
    321   1.1  christos 		strlcpy(timestr, str, sizeof(timestr));
    322   1.1  christos 		timestr[n] = 0;
    323   1.4  christos 		if (n == 8u) {
    324   1.1  christos 			strlcat(timestr, "000000", sizeof(timestr));
    325   1.4  christos 		}
    326   1.1  christos 		result = dns_time64_fromtext(timestr, &val);
    327   1.4  christos 		if (result != ISC_R_SUCCESS) {
    328   1.1  christos 			fatal("time value %s is invalid: %s", orig,
    329   1.1  christos 			      isc_result_totext(result));
    330   1.4  christos 		}
    331   1.1  christos 		base = val;
    332   1.1  christos 		str += n;
    333   1.9  christos 	} else if (n == 10u &&
    334   1.9  christos 		   (str[n] == '\0' || str[n] == '-' || str[n] == '+'))
    335   1.9  christos 	{
    336   1.9  christos 		base = strtoll(str, &endp, 0);
    337   1.9  christos 		str += 10;
    338   1.1  christos 	} else if (strncmp(str, "now", 3) == 0) {
    339   1.1  christos 		base = now;
    340   1.1  christos 		str += 3;
    341   1.9  christos 	} else if (str[0] >= 'A' && str[0] <= 'Z') {
    342   1.9  christos 		/* parse ctime() format as written by `dnssec-settime -p` */
    343   1.9  christos 		endp = isc_tm_strptime(str, "%a %b %d %H:%M:%S %Y", &tm);
    344   1.9  christos 		if (endp != str + 24) {
    345   1.9  christos 			fatal("time value %s is invalid", orig);
    346   1.9  christos 		}
    347   1.9  christos 		base = mktime(&tm);
    348   1.9  christos 		str += 24;
    349   1.1  christos 	}
    350   1.1  christos 
    351   1.4  christos 	if (str[0] == '\0') {
    352  1.11  christos 		return (isc_stdtime_t)base;
    353   1.4  christos 	} else if (str[0] == '+') {
    354   1.1  christos 		offset = strtol(str + 1, &endp, 0);
    355   1.4  christos 		offset = time_units((isc_stdtime_t)offset, endp, orig);
    356   1.1  christos 		val = base + offset;
    357   1.1  christos 	} else if (str[0] == '-') {
    358   1.1  christos 		offset = strtol(str + 1, &endp, 0);
    359   1.4  christos 		offset = time_units((isc_stdtime_t)offset, endp, orig);
    360   1.1  christos 		val = base - offset;
    361   1.4  christos 	} else {
    362   1.1  christos 		fatal("time value %s is invalid", orig);
    363   1.4  christos 	}
    364   1.1  christos 
    365  1.11  christos 	return (isc_stdtime_t)val;
    366   1.1  christos }
    367   1.1  christos 
    368   1.1  christos dns_rdataclass_t
    369   1.1  christos strtoclass(const char *str) {
    370   1.1  christos 	isc_textregion_t r;
    371   1.1  christos 	dns_rdataclass_t rdclass;
    372   1.4  christos 	isc_result_t result;
    373   1.1  christos 
    374   1.4  christos 	if (str == NULL) {
    375  1.11  christos 		return dns_rdataclass_in;
    376   1.4  christos 	}
    377  1.11  christos 	r.base = UNCONST(str);
    378   1.1  christos 	r.length = strlen(str);
    379   1.4  christos 	result = dns_rdataclass_fromtext(&rdclass, &r);
    380   1.4  christos 	if (result != ISC_R_SUCCESS) {
    381   1.1  christos 		fatal("unknown class %s", str);
    382   1.4  christos 	}
    383  1.11  christos 	return rdclass;
    384   1.1  christos }
    385   1.1  christos 
    386   1.1  christos unsigned int
    387   1.4  christos strtodsdigest(const char *str) {
    388   1.4  christos 	isc_textregion_t r;
    389   1.4  christos 	dns_dsdigest_t alg;
    390   1.4  christos 	isc_result_t result;
    391   1.4  christos 
    392  1.11  christos 	r.base = UNCONST(str);
    393   1.4  christos 	r.length = strlen(str);
    394   1.4  christos 	result = dns_dsdigest_fromtext(&alg, &r);
    395   1.4  christos 	if (result != ISC_R_SUCCESS) {
    396   1.4  christos 		fatal("unknown DS algorithm %s", str);
    397   1.4  christos 	}
    398  1.11  christos 	return alg;
    399   1.4  christos }
    400   1.4  christos 
    401   1.4  christos static int
    402   1.4  christos cmp_dtype(const void *ap, const void *bp) {
    403   1.4  christos 	int a = *(const uint8_t *)ap;
    404   1.4  christos 	int b = *(const uint8_t *)bp;
    405  1.11  christos 	return a - b;
    406   1.4  christos }
    407   1.4  christos 
    408   1.4  christos void
    409   1.4  christos add_dtype(unsigned int dt) {
    410  1.11  christos 	unsigned int i, n;
    411   1.4  christos 
    412   1.4  christos 	/* ensure there is space for a zero terminator */
    413   1.4  christos 	n = sizeof(dtype) / sizeof(dtype[0]) - 1;
    414   1.4  christos 	for (i = 0; i < n; i++) {
    415   1.4  christos 		if (dtype[i] == dt) {
    416   1.4  christos 			return;
    417   1.4  christos 		}
    418   1.4  christos 		if (dtype[i] == 0) {
    419   1.4  christos 			dtype[i] = dt;
    420   1.4  christos 			qsort(dtype, i + 1, 1, cmp_dtype);
    421   1.4  christos 			return;
    422   1.4  christos 		}
    423   1.1  christos 	}
    424   1.4  christos 	fatal("too many -a digest type arguments");
    425   1.1  christos }
    426   1.1  christos 
    427   1.1  christos isc_result_t
    428   1.1  christos try_dir(const char *dirname) {
    429   1.1  christos 	isc_result_t result;
    430   1.1  christos 	isc_dir_t d;
    431   1.1  christos 
    432   1.1  christos 	isc_dir_init(&d);
    433   1.1  christos 	result = isc_dir_open(&d, dirname);
    434   1.1  christos 	if (result == ISC_R_SUCCESS) {
    435   1.1  christos 		isc_dir_close(&d);
    436   1.1  christos 	}
    437  1.11  christos 	return result;
    438   1.1  christos }
    439   1.1  christos 
    440   1.1  christos /*
    441   1.1  christos  * Check private key version compatibility.
    442   1.1  christos  */
    443   1.1  christos void
    444   1.1  christos check_keyversion(dst_key_t *key, char *keystr) {
    445   1.1  christos 	int major, minor;
    446   1.1  christos 	dst_key_getprivateformat(key, &major, &minor);
    447   1.1  christos 	INSIST(major <= DST_MAJOR_VERSION); /* invalid private key */
    448   1.1  christos 
    449   1.4  christos 	if (major < DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) {
    450   1.1  christos 		fatal("Key %s has incompatible format version %d.%d, "
    451   1.1  christos 		      "use -f to force upgrade to new version.",
    452   1.1  christos 		      keystr, major, minor);
    453   1.4  christos 	}
    454   1.4  christos 	if (minor > DST_MINOR_VERSION) {
    455   1.1  christos 		fatal("Key %s has incompatible format version %d.%d, "
    456   1.1  christos 		      "use -f to force downgrade to current version.",
    457   1.1  christos 		      keystr, major, minor);
    458   1.4  christos 	}
    459   1.1  christos }
    460   1.1  christos 
    461   1.1  christos void
    462   1.1  christos set_keyversion(dst_key_t *key) {
    463   1.1  christos 	int major, minor;
    464   1.1  christos 	dst_key_getprivateformat(key, &major, &minor);
    465   1.1  christos 	INSIST(major <= DST_MAJOR_VERSION);
    466   1.1  christos 
    467   1.4  christos 	if (major != DST_MAJOR_VERSION || minor != DST_MINOR_VERSION) {
    468   1.1  christos 		dst_key_setprivateformat(key, DST_MAJOR_VERSION,
    469   1.1  christos 					 DST_MINOR_VERSION);
    470   1.4  christos 	}
    471   1.1  christos 
    472   1.1  christos 	/*
    473   1.1  christos 	 * If the key is from a version older than 1.3, set
    474   1.1  christos 	 * set the creation date
    475   1.1  christos 	 */
    476   1.1  christos 	if (major < 1 || (major == 1 && minor <= 2)) {
    477  1.11  christos 		isc_stdtime_t now = isc_stdtime_now();
    478   1.1  christos 		dst_key_settime(key, DST_TIME_CREATED, now);
    479   1.1  christos 	}
    480   1.1  christos }
    481   1.1  christos 
    482   1.3  christos bool
    483   1.1  christos key_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir,
    484  1.11  christos 	      isc_mem_t *mctx, uint16_t min, uint16_t max, bool *exact) {
    485   1.1  christos 	isc_result_t result;
    486   1.3  christos 	bool conflict = false;
    487   1.1  christos 	dns_dnsseckeylist_t matchkeys;
    488   1.1  christos 	dns_dnsseckey_t *key = NULL;
    489   1.3  christos 	uint16_t id, oldid;
    490   1.3  christos 	uint32_t rid, roldid;
    491   1.1  christos 	dns_secalg_t alg;
    492  1.11  christos 	isc_stdtime_t now = isc_stdtime_now();
    493   1.1  christos 
    494  1.12  christos 	SET_IF_NOT_NULL(exact, false);
    495   1.1  christos 
    496   1.1  christos 	id = dst_key_id(dstkey);
    497   1.1  christos 	rid = dst_key_rid(dstkey);
    498   1.1  christos 	alg = dst_key_alg(dstkey);
    499   1.1  christos 
    500  1.11  christos 	if (min != max) {
    501  1.11  christos 		if (id < min || id > max) {
    502  1.11  christos 			fprintf(stderr, "Key ID %d outside of [%u..%u]\n", id,
    503  1.11  christos 				min, max);
    504  1.11  christos 			return true;
    505  1.11  christos 		}
    506  1.11  christos 		if (rid < min || rid > max) {
    507  1.11  christos 			fprintf(stderr,
    508  1.11  christos 				"Revoked Key ID %d (for tag %d) outside of "
    509  1.11  christos 				"[%u..%u]\n",
    510  1.11  christos 				rid, id, min, max);
    511  1.11  christos 			return true;
    512   1.4  christos 		}
    513   1.1  christos 	}
    514   1.1  christos 
    515   1.1  christos 	ISC_LIST_INIT(matchkeys);
    516  1.11  christos 	result = dns_dnssec_findmatchingkeys(name, NULL, dir, NULL, now, mctx,
    517  1.11  christos 					     &matchkeys);
    518   1.4  christos 	if (result == ISC_R_NOTFOUND) {
    519  1.11  christos 		return false;
    520   1.4  christos 	}
    521   1.1  christos 
    522   1.1  christos 	while (!ISC_LIST_EMPTY(matchkeys) && !conflict) {
    523   1.1  christos 		key = ISC_LIST_HEAD(matchkeys);
    524   1.4  christos 		if (dst_key_alg(key->key) != alg) {
    525   1.1  christos 			goto next;
    526   1.4  christos 		}
    527   1.1  christos 
    528   1.1  christos 		oldid = dst_key_id(key->key);
    529   1.1  christos 		roldid = dst_key_rid(key->key);
    530   1.1  christos 
    531   1.1  christos 		if (oldid == rid || roldid == id || id == oldid) {
    532   1.3  christos 			conflict = true;
    533   1.1  christos 			if (id != oldid) {
    534   1.4  christos 				if (verbose > 1) {
    535   1.4  christos 					fprintf(stderr,
    536   1.4  christos 						"Key ID %d could "
    537   1.1  christos 						"collide with %d\n",
    538   1.1  christos 						id, oldid);
    539   1.4  christos 				}
    540   1.1  christos 			} else {
    541   1.4  christos 				if (exact != NULL) {
    542   1.3  christos 					*exact = true;
    543   1.4  christos 				}
    544   1.4  christos 				if (verbose > 1) {
    545   1.1  christos 					fprintf(stderr, "Key ID %d exists\n",
    546   1.1  christos 						id);
    547   1.4  christos 				}
    548   1.1  christos 			}
    549   1.1  christos 		}
    550   1.1  christos 
    551   1.4  christos 	next:
    552   1.1  christos 		ISC_LIST_UNLINK(matchkeys, key, link);
    553   1.1  christos 		dns_dnsseckey_destroy(mctx, &key);
    554   1.1  christos 	}
    555   1.1  christos 
    556   1.1  christos 	/* Finish freeing the list */
    557   1.1  christos 	while (!ISC_LIST_EMPTY(matchkeys)) {
    558   1.1  christos 		key = ISC_LIST_HEAD(matchkeys);
    559   1.1  christos 		ISC_LIST_UNLINK(matchkeys, key, link);
    560   1.1  christos 		dns_dnsseckey_destroy(mctx, &key);
    561   1.1  christos 	}
    562   1.1  christos 
    563  1.11  christos 	return conflict;
    564   1.1  christos }
    565   1.1  christos 
    566   1.3  christos bool
    567   1.4  christos isoptarg(const char *arg, char **argv, void (*usage)(void)) {
    568   1.1  christos 	if (!strcasecmp(isc_commandline_argument, arg)) {
    569   1.1  christos 		if (argv[isc_commandline_index] == NULL) {
    570   1.1  christos 			fprintf(stderr, "%s: missing argument -%c %s\n",
    571   1.1  christos 				program, isc_commandline_option,
    572   1.1  christos 				isc_commandline_argument);
    573   1.1  christos 			usage();
    574   1.1  christos 		}
    575   1.1  christos 		isc_commandline_argument = argv[isc_commandline_index];
    576   1.4  christos 		/* skip to next argument */
    577   1.1  christos 		isc_commandline_index++;
    578  1.11  christos 		return true;
    579  1.11  christos 	}
    580  1.11  christos 	return false;
    581  1.11  christos }
    582  1.11  christos 
    583  1.11  christos void
    584  1.11  christos loadjournal(isc_mem_t *mctx, dns_db_t *db, const char *file) {
    585  1.11  christos 	dns_journal_t *jnl = NULL;
    586  1.11  christos 	isc_result_t result;
    587  1.11  christos 
    588  1.11  christos 	result = dns_journal_open(mctx, file, DNS_JOURNAL_READ, &jnl);
    589  1.11  christos 	if (result == ISC_R_NOTFOUND) {
    590  1.11  christos 		fprintf(stderr, "%s: journal file %s not found\n", program,
    591  1.11  christos 			file);
    592  1.11  christos 		goto cleanup;
    593  1.11  christos 	} else if (result != ISC_R_SUCCESS) {
    594  1.11  christos 		fatal("unable to open journal %s: %s\n", file,
    595  1.11  christos 		      isc_result_totext(result));
    596  1.11  christos 	}
    597  1.11  christos 
    598  1.11  christos 	if (dns_journal_empty(jnl)) {
    599  1.11  christos 		dns_journal_destroy(&jnl);
    600  1.11  christos 		return;
    601  1.11  christos 	}
    602  1.11  christos 
    603  1.11  christos 	result = dns_journal_rollforward(jnl, db, 0);
    604  1.11  christos 	switch (result) {
    605  1.11  christos 	case ISC_R_SUCCESS:
    606  1.11  christos 	case DNS_R_UPTODATE:
    607  1.11  christos 		break;
    608  1.11  christos 
    609  1.11  christos 	case ISC_R_NOTFOUND:
    610  1.11  christos 	case ISC_R_RANGE:
    611  1.11  christos 		fatal("journal %s out of sync with zone", file);
    612  1.11  christos 
    613  1.11  christos 	default:
    614  1.11  christos 		fatal("journal %s: %s\n", file, isc_result_totext(result));
    615  1.11  christos 	}
    616  1.11  christos 
    617  1.11  christos cleanup:
    618  1.11  christos 	dns_journal_destroy(&jnl);
    619  1.11  christos }
    620  1.11  christos 
    621  1.11  christos void
    622  1.11  christos kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, isc_log_t *lctx,
    623  1.11  christos 	       const char *name, const char *keydir, const char *engine,
    624  1.11  christos 	       dns_kasp_t **kaspp) {
    625  1.11  christos 	isc_result_t result = ISC_R_NOTFOUND;
    626  1.11  christos 	const cfg_listelt_t *element;
    627  1.11  christos 	const cfg_obj_t *kasps = NULL;
    628  1.11  christos 	dns_kasp_t *kasp = NULL, *kasp_next;
    629  1.11  christos 	dns_kasplist_t kasplist;
    630  1.11  christos 	const cfg_obj_t *keystores = NULL;
    631  1.11  christos 	dns_keystore_t *ks = NULL, *ks_next;
    632  1.11  christos 	dns_keystorelist_t kslist;
    633  1.11  christos 
    634  1.11  christos 	ISC_LIST_INIT(kasplist);
    635  1.11  christos 	ISC_LIST_INIT(kslist);
    636  1.11  christos 
    637  1.11  christos 	(void)cfg_map_get(config, "key-store", &keystores);
    638  1.11  christos 	for (element = cfg_list_first(keystores); element != NULL;
    639  1.11  christos 	     element = cfg_list_next(element))
    640  1.11  christos 	{
    641  1.11  christos 		cfg_obj_t *kconfig = cfg_listelt_value(element);
    642  1.11  christos 		ks = NULL;
    643  1.11  christos 		result = cfg_keystore_fromconfig(kconfig, mctx, lctx, engine,
    644  1.11  christos 						 &kslist, NULL);
    645  1.11  christos 		if (result != ISC_R_SUCCESS) {
    646  1.11  christos 			fatal("failed to configure key-store '%s': %s",
    647  1.11  christos 			      cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
    648  1.11  christos 			      isc_result_totext(result));
    649  1.11  christos 		}
    650  1.11  christos 	}
    651  1.11  christos 	/* Default key-directory key store. */
    652  1.11  christos 	ks = NULL;
    653  1.11  christos 	(void)cfg_keystore_fromconfig(NULL, mctx, lctx, engine, &kslist, &ks);
    654  1.11  christos 	INSIST(ks != NULL);
    655  1.11  christos 	if (keydir != NULL) {
    656  1.11  christos 		/* '-K keydir' takes priority */
    657  1.11  christos 		dns_keystore_setdirectory(ks, keydir);
    658  1.11  christos 	}
    659  1.11  christos 	dns_keystore_detach(&ks);
    660  1.11  christos 
    661  1.11  christos 	(void)cfg_map_get(config, "dnssec-policy", &kasps);
    662  1.11  christos 	for (element = cfg_list_first(kasps); element != NULL;
    663  1.11  christos 	     element = cfg_list_next(element))
    664  1.11  christos 	{
    665  1.11  christos 		cfg_obj_t *kconfig = cfg_listelt_value(element);
    666  1.11  christos 		kasp = NULL;
    667  1.11  christos 		if (strcmp(cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
    668  1.11  christos 			   name) != 0)
    669  1.11  christos 		{
    670  1.11  christos 			continue;
    671  1.11  christos 		}
    672  1.11  christos 
    673  1.11  christos 		result = cfg_kasp_fromconfig(kconfig, NULL, true, mctx, lctx,
    674  1.11  christos 					     &kslist, &kasplist, &kasp);
    675  1.11  christos 		if (result != ISC_R_SUCCESS) {
    676  1.11  christos 			fatal("failed to configure dnssec-policy '%s': %s",
    677  1.11  christos 			      cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
    678  1.11  christos 			      isc_result_totext(result));
    679  1.11  christos 		}
    680  1.11  christos 		INSIST(kasp != NULL);
    681  1.11  christos 		dns_kasp_freeze(kasp);
    682  1.11  christos 		break;
    683  1.11  christos 	}
    684  1.11  christos 
    685  1.11  christos 	*kaspp = kasp;
    686  1.11  christos 
    687  1.11  christos 	/*
    688  1.11  christos 	 * Cleanup kasp list.
    689  1.11  christos 	 */
    690  1.11  christos 	for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
    691  1.11  christos 		kasp_next = ISC_LIST_NEXT(kasp, link);
    692  1.11  christos 		ISC_LIST_UNLINK(kasplist, kasp, link);
    693  1.11  christos 		dns_kasp_detach(&kasp);
    694  1.11  christos 	}
    695  1.11  christos 
    696  1.11  christos 	/*
    697  1.11  christos 	 * Cleanup keystore list.
    698  1.11  christos 	 */
    699  1.11  christos 	for (ks = ISC_LIST_HEAD(kslist); ks != NULL; ks = ks_next) {
    700  1.11  christos 		ks_next = ISC_LIST_NEXT(ks, link);
    701  1.11  christos 		ISC_LIST_UNLINK(kslist, ks, link);
    702  1.11  christos 		dns_keystore_detach(&ks);
    703   1.1  christos 	}
    704   1.1  christos }
    705