Beispiel #1
0
static void
dh(dns_name_t *name1, int id1, dns_name_t *name2, int id2, isc_mem_t *mctx) {
	dst_key_t *key1 = NULL, *key2 = NULL;
	isc_result_t ret;
	isc_buffer_t b1, b2;
	isc_region_t r1, r2;
	unsigned char array1[1024], array2[1024];
	int alg = DST_ALG_DH;
	int type = DST_TYPE_PUBLIC|DST_TYPE_PRIVATE|DST_TYPE_KEY;

	ret = dst_key_fromfile(name1, id1, alg, type, current, mctx, &key1);
	printf("read(%d) returned: %s\n", alg, isc_result_totext(ret));
	if (ret != 0)
		return;
	ret = dst_key_fromfile(name2, id2, alg, type, current, mctx, &key2);
	printf("read(%d) returned: %s\n", alg, isc_result_totext(ret));
	if (ret != 0)
		return;

	ret = dst_key_tofile(key1, type, tmp);
	printf("write(%d) returned: %s\n", alg, isc_result_totext(ret));
	if (ret != 0)
		return;
	ret = dst_key_tofile(key2, type, tmp);
	printf("write(%d) returned: %s\n", alg, isc_result_totext(ret));
	if (ret != 0)
		return;

	isc_buffer_init(&b1, array1, sizeof(array1));
	ret = dst_key_computesecret(key1, key2, &b1);
	printf("computesecret() returned: %s\n", isc_result_totext(ret));
	if (ret != 0)
		return;

	isc_buffer_init(&b2, array2, sizeof(array2));
	ret = dst_key_computesecret(key2, key1, &b2);
	printf("computesecret() returned: %s\n", isc_result_totext(ret));
	if (ret != 0)
		return;

	isc_buffer_usedregion(&b1, &r1);
	isc_buffer_usedregion(&b2, &r2);

	if (r1.length != r2.length || memcmp(r1.base, r2.base, r1.length) != 0)
	{
		int i;
		printf("secrets don't match\n");
		printf("secret 1: %d bytes\n", r1.length);
		for (i = 0; i < (int) r1.length; i++)
			printf("%02x ", r1.base[i]);
		printf("\n");
		printf("secret 2: %d bytes\n", r2.length);
		for (i = 0; i < (int) r2.length; i++)
			printf("%02x ", r2.base[i]);
		printf("\n");
	}
	dst_key_free(&key1);
	dst_key_free(&key2);
}
Beispiel #2
0
static isc_result_t
compute_secret (isc_buffer_t * shared, isc_region_t * queryrandomness,
                isc_region_t * serverrandomness, isc_buffer_t * secret)
{
    isc_md5_t md5ctx;

    isc_region_t r, r2;

    unsigned char digests[32];

    unsigned int i;

    isc_buffer_usedregion (shared, &r);

    /*
     * MD5 ( query data | DH value ).
     */
    isc_md5_init (&md5ctx);
    isc_md5_update (&md5ctx, queryrandomness->base, queryrandomness->length);
    isc_md5_update (&md5ctx, r.base, r.length);
    isc_md5_final (&md5ctx, digests);

    /*
     * MD5 ( server data | DH value ).
     */
    isc_md5_init (&md5ctx);
    isc_md5_update (&md5ctx, serverrandomness->base, serverrandomness->length);
    isc_md5_update (&md5ctx, r.base, r.length);
    isc_md5_final (&md5ctx, &digests[ISC_MD5_DIGESTLENGTH]);

    /*
     * XOR ( DH value, MD5-1 | MD5-2).
     */
    isc_buffer_availableregion (secret, &r);
    isc_buffer_usedregion (shared, &r2);
    if (r.length < sizeof (digests) || r.length < r2.length)
        return (ISC_R_NOSPACE);
    if (r2.length > sizeof (digests))
    {
        memcpy (r.base, r2.base, r2.length);
        for (i = 0; i < sizeof (digests); i++)
            r.base[i] ^= digests[i];
        isc_buffer_add (secret, r2.length);
    }
    else
    {
        memcpy (r.base, digests, sizeof (digests));
        for (i = 0; i < r2.length; i++)
            r.base[i] ^= r2.base[i];
        isc_buffer_add (secret, sizeof (digests));
    }
    return (ISC_R_SUCCESS);

}
Beispiel #3
0
static void
parse_rdata(isc_mem_t *mctx, char **cmdlinep, dns_rdataclass_t rdataclass,
	    dns_rdatatype_t rdatatype, dns_rdata_t *rdata)
{
	char *cmdline = *cmdlinep;
	isc_buffer_t source, *buf = NULL, *newbuf = NULL;
	isc_region_t r;
	isc_lex_t *lex = NULL;
	dns_rdatacallbacks_t callbacks;
	isc_result_t result;

	while (cmdline != NULL && *cmdline != 0 &&
	       isspace((unsigned char)*cmdline))
		cmdline++;

	if (cmdline != NULL && *cmdline != 0) {
		dns_rdatacallbacks_init(&callbacks);
		result = isc_lex_create(mctx, strlen(cmdline), &lex);
		check_result(result, "isc_lex_create");
		isc_buffer_init(&source, cmdline, strlen(cmdline));
		isc_buffer_add(&source, strlen(cmdline));
		result = isc_lex_openbuffer(lex, &source);
		check_result(result, "isc_lex_openbuffer");
		result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
		check_result(result, "isc_buffer_allocate");
		result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex,
					    dns_rootname, 0, mctx, buf,
					    &callbacks);
		isc_lex_destroy(&lex);
		if (result == ISC_R_SUCCESS) {
			isc_buffer_usedregion(buf, &r);
			result = isc_buffer_allocate(mctx, &newbuf, r.length);
			check_result(result, "isc_buffer_allocate");
			isc_buffer_putmem(newbuf, r.base, r.length);
			isc_buffer_usedregion(newbuf, &r);
			dns_rdata_reset(rdata);
			dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r);
			isc_buffer_free(&buf);
			ISC_LIST_APPEND(usedbuffers, newbuf, link);
		} else {
			fprintf(stderr, "invalid rdata format: %s\n",
				isc_result_totext(result));
			isc_buffer_free(&buf);
			exit(1);
		}
	} else {
		rdata->flags = DNS_RDATA_UPDATE;
	}
	*cmdlinep = cmdline;
}
Beispiel #4
0
static isc_result_t
gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) {
	gssapi_ctx_t *ctx = dctx->opaque;
	isc_region_t message;
	gss_buffer_desc gmessage, gsig;
	OM_uint32 minor, gret;

	isc_buffer_usedregion(ctx->buffer, &message);
	REGION_TO_GBUFFER(message, gmessage);

	gret = gss_get_mic(&minor, ctx->context_id,
			   GSS_C_QOP_DEFAULT, &gmessage, &gsig);
	if (gret != 0)
		return (ISC_R_FAILURE);

	if (gsig.length > isc_buffer_availablelength(sig)) {
		gss_release_buffer(&minor, &gsig);
		return (ISC_R_NOSPACE);
	}

	isc_buffer_putmem(sig, gsig.value, gsig.length);

	gss_release_buffer(&minor, &gsig);

	return (ISC_R_SUCCESS);
}
Beispiel #5
0
static isc_result_t
gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
	gssapi_ctx_t *ctx = dctx->opaque;
	isc_buffer_t *newbuffer = NULL;
	isc_region_t r;
	unsigned int length;
	isc_result_t result;

	result = isc_buffer_copyregion(ctx->buffer, data);
	if (result == ISC_R_SUCCESS)
		return (ISC_R_SUCCESS);

	length = isc_buffer_length(ctx->buffer) + data->length + BUFFER_EXTRA;

	result = isc_buffer_allocate(dctx->mctx, &newbuffer, length);
	if (result != ISC_R_SUCCESS)
		return (result);

	isc_buffer_usedregion(ctx->buffer, &r);
	(void) isc_buffer_copyregion(newbuffer, &r);
	(void) isc_buffer_copyregion(newbuffer, data);

	isc_buffer_free(&ctx->buffer);
	ctx->buffer = newbuffer;

	return (ISC_R_SUCCESS);
}
Beispiel #6
0
isc_result_t
dns_name_digest(dns_name_t *name, dns_digestfunc_t digest, void *arg) {
	dns_name_t downname;
	unsigned char data[256];
	isc_buffer_t buffer;
	isc_result_t result;
	isc_region_t r;

	/*
	 * Send 'name' in DNSSEC canonical form to 'digest'.
	 */

	REQUIRE(VALID_NAME(name));
	REQUIRE(digest != NULL);

	DNS_NAME_INIT(&downname, NULL);
	isc_buffer_init(&buffer, data, sizeof(data));

	result = dns_name_downcase(name, &downname, &buffer);
	if (result != ISC_R_SUCCESS)
		return (result);

	isc_buffer_usedregion(&buffer, &r);

	return ((digest)(arg, &r));
}
Beispiel #7
0
static void print_name (dns_name_t * name)
{
    isc_result_t result;

    isc_buffer_t source;

    isc_region_t r;

    char s[1000];

    isc_buffer_init (&source, s, sizeof (s));
    if (dns_name_countlabels (name) > 0)
        result = dns_name_totext (name, ISC_FALSE, &source);
    else
        result = ISC_R_SUCCESS;
    if (result == ISC_R_SUCCESS)
    {
        isc_buffer_usedregion (&source, &r);
        if (r.length > 0)
            printf ("%.*s\n", (int) r.length, r.base);
        else
            printf ("<empty text name>\n");
    }
    else
        printf ("error: %s\n", dns_result_totext (result));
}
Beispiel #8
0
static inline void
name_to_gbuffer(dns_name_t *name, isc_buffer_t *buffer,
		gss_buffer_desc *gbuffer)
{
	dns_name_t tname, *namep;
	isc_region_t r;
	isc_result_t result;

	if (!dns_name_isabsolute(name))
		namep = name;
	else
	{
		unsigned int labels;
		dns_name_init(&tname, NULL);
		labels = dns_name_countlabels(name);
		dns_name_getlabelsequence(name, 0, labels - 1, &tname);
		namep = &tname;
	}

	result = dns_name_toprincipal(namep, buffer);
	RUNTIME_CHECK(result == ISC_R_SUCCESS);
	isc_buffer_putuint8(buffer, 0);
	isc_buffer_usedregion(buffer, &r);
	REGION_TO_GBUFFER(r, *gbuffer);
}
/*%
 * Verify.
 */
static isc_result_t
gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
	dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
	isc_region_t message, r;
	gss_buffer_desc gmessage, gsig;
	OM_uint32 minor, gret;
	gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
	unsigned char *buf;
	char err[1024];

	/*
	 * Convert the data we wish to sign into a structure gssapi can
	 * understand.
	 */
	isc_buffer_usedregion(ctx->buffer, &message);
	REGION_TO_GBUFFER(message, gmessage);

	/*
	 * XXXMLG
	 * It seem that gss_verify_mic() modifies the signature buffer,
	 * at least on Heimdal's implementation.  Copy it here to an allocated
	 * buffer.
	 */
	buf = isc_mem_allocate(dst__memory_pool, sig->length);
	if (buf == NULL)
		return (ISC_R_FAILURE);
	memmove(buf, sig->base, sig->length);
	r.base = buf;
	r.length = sig->length;
	REGION_TO_GBUFFER(r, gsig);

	/*
	 * Verify the data.
	 */
	gret = gss_verify_mic(&minor, gssctx, &gmessage, &gsig, NULL);

	isc_mem_free(dst__memory_pool, buf);

	/*
	 * Convert return codes into something useful to us.
	 */
	if (gret != GSS_S_COMPLETE) {
		gss_log(3, "GSS verify error: %s",
			gss_error_tostring(gret, minor, err, sizeof(err)));
		if (gret == GSS_S_DEFECTIVE_TOKEN ||
		    gret == GSS_S_BAD_SIG ||
		    gret == GSS_S_DUPLICATE_TOKEN ||
		    gret == GSS_S_OLD_TOKEN ||
		    gret == GSS_S_UNSEQ_TOKEN ||
		    gret == GSS_S_GAP_TOKEN ||
		    gret == GSS_S_CONTEXT_EXPIRED ||
		    gret == GSS_S_NO_CONTEXT ||
		    gret == GSS_S_FAILURE)
			return(DST_R_VERIFYFAILURE);
		else
			return (ISC_R_FAILURE);
	}

	return (ISC_R_SUCCESS);
}
Beispiel #10
0
/* Dump an rdataset for debug */
static isc_result_t print_rdataset (dns_rdataset_t * rdataset, dns_name_t * owner)
{
    isc_buffer_t target;

    isc_result_t result;

    isc_region_t r;

    char t[4096];

    if (!debug_mode)
        return (ISC_R_SUCCESS);

    isc_buffer_init (&target, t, sizeof (t));

    if (!dns_rdataset_isassociated (rdataset))
        return (ISC_R_SUCCESS);
    result = dns_rdataset_totext (rdataset, owner, ISC_FALSE, ISC_FALSE, &target);
    if (result != ISC_R_SUCCESS)
        return (result);
    isc_buffer_usedregion (&target, &r);
    printf ("%.*s", (int) r.length, (char *) r.base);

    return (ISC_R_SUCCESS);
}
Beispiel #11
0
static void
use(dst_key_t *key, isc_mem_t *mctx) {
	isc_result_t ret;
	const char *data = "This is some data";
	unsigned char sig[512];
	isc_buffer_t databuf, sigbuf;
	isc_region_t datareg, sigreg;
	dst_context_t *ctx = NULL;

	isc_buffer_init(&sigbuf, sig, sizeof(sig));
	/*
	 * Advance 1 byte for fun.
	 */
	isc_buffer_add(&sigbuf, 1);

	isc_buffer_init(&databuf, data, strlen(data));
	isc_buffer_add(&databuf, strlen(data));
	isc_buffer_usedregion(&databuf, &datareg);

	ret = dst_context_create(key, mctx, &ctx);
	if (ret != ISC_R_SUCCESS) {
		printf("contextcreate(%d) returned: %s\n", dst_key_alg(key),
		       isc_result_totext(ret));
		return;
	}
	ret = dst_context_adddata(ctx, &datareg);
	if (ret != ISC_R_SUCCESS) {
		printf("adddata(%d) returned: %s\n", dst_key_alg(key),
		       isc_result_totext(ret));
		dst_context_destroy(&ctx);
		return;
	}
	ret = dst_context_sign(ctx, &sigbuf);
	printf("sign(%d) returned: %s\n", dst_key_alg(key),
	       isc_result_totext(ret));
	dst_context_destroy(&ctx);

	isc_buffer_forward(&sigbuf, 1);
	isc_buffer_remainingregion(&sigbuf, &sigreg);
	ret = dst_context_create(key, mctx, &ctx);
	if (ret != ISC_R_SUCCESS) {
		printf("contextcreate(%d) returned: %s\n", dst_key_alg(key),
		       isc_result_totext(ret));
		return;
	}
	ret = dst_context_adddata(ctx, &datareg);
	if (ret != ISC_R_SUCCESS) {
		printf("adddata(%d) returned: %s\n", dst_key_alg(key),
		       isc_result_totext(ret));
		dst_context_destroy(&ctx);
		return;
	}
	ret = dst_context_verify(ctx, &sigreg);
	printf("verify(%d) returned: %s\n", dst_key_alg(key),
	       isc_result_totext(ret));
	dst_context_destroy(&ctx);
}
Beispiel #12
0
void
type_format(const dns_rdatatype_t type, char *cp, unsigned int size) {
	isc_buffer_t b;
	isc_region_t r;
	isc_result_t result;

	isc_buffer_init(&b, cp, size - 1);
	result = dns_rdatatype_totext(type, &b);
	check_result(result, "dns_rdatatype_totext()");
	isc_buffer_usedregion(&b, &r);
	r.base[r.length] = 0;
}
Beispiel #13
0
/*
 * Derived from bind8 ns_format_ttl().
 */
isc_result_t
dns_ttl_totext(isc_uint32_t src, isc_boolean_t verbose, isc_buffer_t *target) {
	unsigned secs, mins, hours, days, weeks, x;

	secs = src % 60;   src /= 60;
	mins = src % 60;   src /= 60;
	hours = src % 24;  src /= 24;
	days = src % 7;    src /= 7;
	weeks = src;       src = 0;

	x = 0;
	if (weeks != 0) {
		RETERR(ttlfmt(weeks, "week", verbose, ISC_TF(x > 0), target));
		x++;
	}
	if (days != 0) {
		RETERR(ttlfmt(days, "day", verbose, ISC_TF(x > 0), target));
		x++;
	}
	if (hours != 0) {
		RETERR(ttlfmt(hours, "hour", verbose, ISC_TF(x > 0), target));
		x++;
	}
	if (mins != 0) {
		RETERR(ttlfmt(mins, "minute", verbose, ISC_TF(x > 0), target));
		x++;
	}
	if (secs != 0 ||
	    (weeks == 0 && days == 0 && hours == 0 && mins == 0)) {
		RETERR(ttlfmt(secs, "second", verbose, ISC_TF(x > 0), target));
		x++;
	}
	INSIST (x > 0);
	/*
	 * If only a single unit letter is printed, print it
	 * in upper case. (Why?  Because BIND 8 does that.
	 * Presumably it has a reason.)
	 */
	if (x == 1 && !verbose) {
		isc_region_t region;
		/*
		 * The unit letter is the last character in the
		 * used region of the buffer.
		 *
		 * toupper() does not need its argument to be masked of cast
		 * here because region.base is type unsigned char *.
		 */
		isc_buffer_usedregion(target, &region);
		region.base[region.length - 1] =
			toupper(region.base[region.length - 1]);
	}
	return (ISC_R_SUCCESS);
}
Beispiel #14
0
/*
 * Compares only the public portion of two keys, by converting them
 * both to wire format and comparing the results.
 */
static isc_boolean_t
pub_compare(const dst_key_t *key1, const dst_key_t *key2) {
	isc_result_t result;
	unsigned char buf1[DST_KEY_MAXSIZE], buf2[DST_KEY_MAXSIZE];
	isc_buffer_t b1, b2;
	isc_region_t r1, r2;

	isc_buffer_init(&b1, buf1, sizeof(buf1));
	result = dst_key_todns(key1, &b1);
	if (result != ISC_R_SUCCESS)
		return (ISC_FALSE);
	/* Zero out flags. */
	buf1[0] = buf1[1] = 0;
	if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
		isc_buffer_subtract(&b1, 2);

	isc_buffer_init(&b2, buf2, sizeof(buf2));
	result = dst_key_todns(key2, &b2);
	if (result != ISC_R_SUCCESS)
		return (ISC_FALSE);
	/* Zero out flags. */
	buf2[0] = buf2[1] = 0;
	if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
		isc_buffer_subtract(&b2, 2);

	isc_buffer_usedregion(&b1, &r1);
	/* Remove extended flags. */
	if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
		memmove(&buf1[4], &buf1[6], r1.length - 6);
		r1.length -= 2;
	}

	isc_buffer_usedregion(&b2, &r2);
	/* Remove extended flags. */
	if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
		memmove(&buf2[4], &buf2[6], r2.length - 6);
		r2.length -= 2;
	}
	return (ISC_TF(isc_region_compare(&r1, &r2) == 0));
}
Beispiel #15
0
static isc_result_t
add_mac(dst_context_t *tsigctx, isc_buffer_t *buf) {
	dns_rdata_any_tsig_t tsig;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	isc_buffer_t databuf;
	isc_region_t r;
	isc_result_t result;
	unsigned char tsigbuf[1024];

	isc_buffer_usedregion(buf, &r);
	dns_rdata_fromregion(&rdata, dns_rdataclass_any,
			     dns_rdatatype_tsig, &r);
	isc_buffer_init(&databuf, tsigbuf, sizeof(tsigbuf));
	CHECK(dns_rdata_tostruct(&rdata, &tsig, NULL));
	isc_buffer_putuint16(&databuf, tsig.siglen);
	isc_buffer_putmem(&databuf, tsig.signature, tsig.siglen);
	isc_buffer_usedregion(&databuf, &r);
	result = dst_context_adddata(tsigctx, &r);
	dns_rdata_freestruct(&tsig);
 cleanup:
	return (result);
}
/*%
 * Sign.
 */
static isc_result_t
gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) {
	dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
	isc_region_t message;
	gss_buffer_desc gmessage, gsig;
	OM_uint32 minor, gret;
	gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
	char buf[1024];

	/*
	 * Convert the data we wish to sign into a structure gssapi can
	 * understand.
	 */
	isc_buffer_usedregion(ctx->buffer, &message);
	REGION_TO_GBUFFER(message, gmessage);

	/*
	 * Generate the signature.
	 */
	gret = gss_get_mic(&minor, gssctx, GSS_C_QOP_DEFAULT, &gmessage,
			   &gsig);

	/*
	 * If it did not complete, we log the result and return a generic
	 * failure code.
	 */
	if (gret != GSS_S_COMPLETE) {
		gss_log(3, "GSS sign error: %s",
			gss_error_tostring(gret, minor, buf, sizeof(buf)));
		return (ISC_R_FAILURE);
	}

	/*
	 * If it will not fit in our allocated buffer, return that we need
	 * more space.
	 */
	if (gsig.length > isc_buffer_availablelength(sig)) {
		gss_release_buffer(&minor, &gsig);
		return (ISC_R_NOSPACE);
	}

	/*
	 * Copy the output into our buffer space, and release the gssapi
	 * allocated space.
	 */
	isc_buffer_putmem(sig, gsig.value, (unsigned int)gsig.length);
	if (gsig.length != 0U)
		gss_release_buffer(&minor, &gsig);

	return (ISC_R_SUCCESS);
}
Beispiel #17
0
void
dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size) {
	isc_buffer_t b;
	isc_region_t r;
	isc_result_t result;

	REQUIRE(cp != NULL && size > 0);
	isc_buffer_init(&b, cp, size - 1);
	result = dns_secalg_totext(alg, &b);
	isc_buffer_usedregion(&b, &r);
	r.base[r.length] = 0;
	if (result != ISC_R_SUCCESS)
		r.base[0] = 0;
}
Beispiel #18
0
static void
dns(dst_key_t *key, isc_mem_t *mctx) {
	unsigned char buffer1[2048];
	unsigned char buffer2[2048];
	isc_buffer_t buf1, buf2;
	isc_region_t r1, r2;
	dst_key_t *newkey = NULL;
	isc_result_t ret;
	isc_boolean_t match;

	isc_buffer_init(&buf1, buffer1, sizeof(buffer1));
	ret = dst_key_todns(key, &buf1);
	printf("todns(%d) returned: %s\n", dst_key_alg(key),
	       isc_result_totext(ret));
	if (ret != ISC_R_SUCCESS)
		return;
	ret = dst_key_fromdns(dst_key_name(key), dns_rdataclass_in,
			      &buf1, mctx, &newkey);
	printf("fromdns(%d) returned: %s\n", dst_key_alg(key),
	       isc_result_totext(ret));
	if (ret != ISC_R_SUCCESS)
		return;
	isc_buffer_init(&buf2, buffer2, sizeof(buffer2));
	ret = dst_key_todns(newkey, &buf2);
	printf("todns2(%d) returned: %s\n", dst_key_alg(key),
	       isc_result_totext(ret));
	if (ret != ISC_R_SUCCESS)
		return;
	isc_buffer_usedregion(&buf1, &r1);
	isc_buffer_usedregion(&buf2, &r2);
	match = ISC_TF(r1.length == r2.length &&
		       memcmp(r1.base, r2.base, r1.length) == 0);
	printf("compare(%d): %s\n", dst_key_alg(key),
	       match ? "true" : "false");
	dst_key_free(&newkey);
}
Beispiel #19
0
static isc_result_t
computeid(dst_key_t *key) {
	isc_buffer_t dnsbuf;
	unsigned char dns_array[DST_KEY_MAXSIZE];
	isc_region_t r;
	isc_result_t ret;

	isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
	ret = dst_key_todns(key, &dnsbuf);
	if (ret != ISC_R_SUCCESS)
		return (ret);

	isc_buffer_usedregion(&dnsbuf, &r);
	key->key_id = dst_region_computeid(&r, key->key_alg);
	return (ISC_R_SUCCESS);
}
Beispiel #20
0
static void
print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset) {
	isc_buffer_t text;
	char t[1000];
	isc_result_t result;
	isc_region_t r;

	isc_buffer_init(&text, t, sizeof(t));
	result = dns_rdataset_totext(rdataset, name, ISC_FALSE, ISC_FALSE,
				     &text);
	isc_buffer_usedregion(&text, &r);
	if (result == ISC_R_SUCCESS)
		printf("%.*s", (int)r.length, (char *)r.base);
	else
		printf("%s\n", dns_result_totext(result));
}
Beispiel #21
0
static isc_result_t
print_name(dns_name_t *name) {
	isc_result_t result;
	isc_buffer_t target;
	isc_region_t r;
	char t[4096];

	isc_buffer_init(&target, t, sizeof(t));
	result = dns_name_totext(name, ISC_TRUE, &target);
	if (result == ISC_R_SUCCESS) {
		isc_buffer_usedregion(&target, &r);
		printf("%.*s", (int)r.length, (char *)r.base);
	} else
		printf("(invalid name)");

	return (result);
}
Beispiel #22
0
/*%
 * Write key timing metadata to a file pointer, preceded by 'tag'
 */
static void
printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
	isc_result_t result;
#ifdef ISC_PLATFORM_USETHREADS
	char output[26]; /* Minimum buffer as per ctime_r() specification. */
#else
	const char *output;
#endif
	isc_stdtime_t when;
	time_t t;
	char utc[sizeof("YYYYMMDDHHSSMM")];
	isc_buffer_t b;
	isc_region_t r;

	result = dst_key_gettime(key, type, &when);
	if (result == ISC_R_NOTFOUND)
		return;

	/* time_t and isc_stdtime_t might be different sizes */
	t = when;
#ifdef ISC_PLATFORM_USETHREADS
#ifdef WIN32
	if (ctime_s(output, sizeof(output), &t) != 0)
		goto error;
#else
	if (ctime_r(&t, output) == NULL)
		goto error;
#endif
#else
	output = ctime(&t);
#endif

	isc_buffer_init(&b, utc, sizeof(utc));
	result = dns_time32_totext(when, &b);
	if (result != ISC_R_SUCCESS)
		goto error;

	isc_buffer_usedregion(&b, &r);
	fprintf(stream, "%s: %.*s (%.*s)\n", tag, (int)r.length, r.base,
		 (int)strlen(output) - 1, output);
	return;

 error:
	fprintf(stream, "%s: (set, unable to display)\n", tag);
}
Beispiel #23
0
static isc_result_t
gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
	gssapi_ctx_t *ctx = dctx->opaque;
	isc_region_t message;
	gss_buffer_desc gmessage, gsig;
	OM_uint32 minor, gret;

	isc_buffer_usedregion(ctx->buffer, &message);
	REGION_TO_GBUFFER(message, gmessage);

	REGION_TO_GBUFFER(*sig, gsig);

	gret = gss_verify_mic(&minor, ctx->context_id, &gmessage, &gsig, NULL);
	if (gret != 0)
		return (ISC_R_FAILURE);

	return (ISC_R_SUCCESS);
}
Beispiel #24
0
static void
print_section(dns_message_t *message, int section, isc_buffer_t *buf) {
	isc_result_t result;
	isc_region_t r;

	result = dns_message_sectiontotext(message, section,
					   &dns_master_style_full, 0, buf);
	if (result != ISC_R_SUCCESS)
		goto fail;

	isc_buffer_usedregion(buf, &r);
	printf("%.*s", (int)r.length, (char *)r.base);

	return;

 fail:
	fprintf(stderr, "failed to convert a section\n");
}
Beispiel #25
0
static void
loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size,
	dns_rdata_t *rdata)
{
	isc_result_t  result;
	dst_key_t     *key = NULL;
	isc_buffer_t  keyb;
	isc_region_t  r;

	dns_rdata_init(rdata);

	isc_buffer_init(&keyb, key_buf, key_buf_size);

	result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC,
				       mctx, &key);
	if (result != ISC_R_SUCCESS)
		fatal("invalid keyfile name %s: %s",
		      filename, isc_result_totext(result));

	if (verbose > 2) {
		char keystr[DST_KEY_FORMATSIZE];

		dst_key_format(key, keystr, sizeof(keystr));
		fprintf(stderr, "%s: %s\n", program, keystr);
	}

	result = dst_key_todns(key, &keyb);
	if (result != ISC_R_SUCCESS)
		fatal("can't decode key");

	isc_buffer_usedregion(&keyb, &r);
	dns_rdata_fromregion(rdata, dst_key_class(key),
			     dns_rdatatype_dnskey, &r);

	rdclass = dst_key_class(key);

	dns_fixedname_init(&fixed);
	name = dns_fixedname_name(&fixed);
	result = dns_name_copy(dst_key_name(key), name, NULL);
	if (result != ISC_R_SUCCESS)
		fatal("can't copy name");

	dst_key_free(&key);
}
Beispiel #26
0
isc_result_t
isc_buffer_dup(isc_mem_t *mctx, isc_buffer_t **dstp, const isc_buffer_t *src) {
	isc_buffer_t *dst = NULL;
	isc_region_t region;
	isc_result_t result;

	REQUIRE(dstp != NULL && *dstp == NULL);
	REQUIRE(ISC_BUFFER_VALID(src));

	isc_buffer_usedregion(src, &region);

	result = isc_buffer_allocate(mctx, &dst, region.length);
	if (result != ISC_R_SUCCESS)
		return (result);

	result = isc_buffer_copyregion(dst, &region);
	RUNTIME_CHECK(result == ISC_R_SUCCESS); /* NOSPACE is impossible */
	*dstp = dst;
	return (ISC_R_SUCCESS);
}
Beispiel #27
0
isc_result_t
dns_name_print(dns_name_t *name, FILE *stream) {
	isc_result_t result;
	isc_buffer_t b;
	isc_region_t r;
	char t[1024];

	/*
	 * Print 'name' on 'stream'.
	 */

	REQUIRE(VALID_NAME(name));

	isc_buffer_init(&b, t, sizeof(t));
	result = dns_name_totext(name, ISC_FALSE, &b);
	if (result != ISC_R_SUCCESS)
		return (result);
	isc_buffer_usedregion(&b, &r);
	fprintf(stream, "%.*s", (int)r.length, (char *)r.base);

	return (ISC_R_SUCCESS);
}
Beispiel #28
0
void
dns_name_format(dns_name_t *name, char *cp, unsigned int size) {
	isc_result_t result;
	isc_buffer_t buf;

	REQUIRE(size > 0);

	/*
	 * Leave room for null termination after buffer.
	 */
	isc_buffer_init(&buf, cp, size - 1);
	result = dns_name_totext(name, ISC_TRUE, &buf);
	if (result == ISC_R_SUCCESS) {
		/*
		 * Null terminate.
		 */
		isc_region_t r;
		isc_buffer_usedregion(&buf, &r);
		((char *) r.base)[r.length] = '\0';

	} else
		snprintf(cp, size, "<unknown>");
}
Beispiel #29
0
/*
 * Arrange to send as much as we can of "stream" without blocking.
 *
 * Requires:
 *	The stream iterator is initialized and points at an RR,
 *      or possibly at the end of the stream (that is, the
 *      _first method of the iterator has been called).
 */
static void
sendstream(xfrout_ctx_t *xfr) {
	dns_message_t *tcpmsg = NULL;
	dns_message_t *msg = NULL; /* Client message if UDP, tcpmsg if TCP */
	isc_result_t result;
	isc_region_t used;
	isc_region_t region;
	dns_rdataset_t *qrdataset;
	dns_name_t *msgname = NULL;
	dns_rdata_t *msgrdata = NULL;
	dns_rdatalist_t *msgrdl = NULL;
	dns_rdataset_t *msgrds = NULL;
	dns_compress_t cctx;
	isc_boolean_t cleanup_cctx = ISC_FALSE;
	isc_boolean_t is_tcp;

	int n_rrs;

	isc_buffer_clear(&xfr->buf);
	isc_buffer_clear(&xfr->txlenbuf);
	isc_buffer_clear(&xfr->txbuf);

	is_tcp = ISC_TF((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0);
	if (!is_tcp) {
		/*
		 * In the UDP case, we put the response data directly into
		 * the client message.
		 */
		msg = xfr->client->message;
		CHECK(dns_message_reply(msg, ISC_TRUE));
	} else {
		/*
		 * TCP. Build a response dns_message_t, temporarily storing
		 * the raw, uncompressed owner names and RR data contiguously
		 * in xfr->buf.  We know that if the uncompressed data fits
		 * in xfr->buf, the compressed data will surely fit in a TCP
		 * message.
		 */

		CHECK(dns_message_create(xfr->mctx,
					 DNS_MESSAGE_INTENTRENDER, &tcpmsg));
		msg = tcpmsg;

		msg->id = xfr->id;
		msg->rcode = dns_rcode_noerror;
		msg->flags = DNS_MESSAGEFLAG_QR | DNS_MESSAGEFLAG_AA;
		if ((xfr->client->attributes & NS_CLIENTATTR_RA) != 0)
			msg->flags |= DNS_MESSAGEFLAG_RA;
		CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
		CHECK(dns_message_setquerytsig(msg, xfr->lasttsig));
		if (xfr->lasttsig != NULL)
			isc_buffer_free(&xfr->lasttsig);

		/*
		 * Add a EDNS option to the message?
		 */
		if ((xfr->client->attributes & NS_CLIENTATTR_WANTOPT) != 0) {
			dns_rdataset_t *opt = NULL;

			CHECK(ns_client_addopt(xfr->client, msg, &opt));
			CHECK(dns_message_setopt(msg, opt));
			/*
			 * Add to first message only.
			 */
			xfr->client->attributes &= ~NS_CLIENTATTR_WANTNSID;
			xfr->client->attributes &= ~NS_CLIENTATTR_HAVEEXPIRE;
		}

		/*
		 * Account for reserved space.
		 */
		if (xfr->tsigkey != NULL)
			INSIST(msg->reserved != 0U);
		isc_buffer_add(&xfr->buf, msg->reserved);

		/*
		 * Include a question section in the first message only.
		 * BIND 8.2.1 will not recognize an IXFR if it does not
		 * have a question section.
		 */
		if (xfr->nmsg == 0) {
			dns_name_t *qname = NULL;
			isc_region_t r;

			/*
			 * Reserve space for the 12-byte message header
			 * and 4 bytes of question.
			 */
			isc_buffer_add(&xfr->buf, 12 + 4);

			qrdataset = NULL;
			result = dns_message_gettemprdataset(msg, &qrdataset);
			if (result != ISC_R_SUCCESS)
				goto failure;
			dns_rdataset_makequestion(qrdataset,
					xfr->client->message->rdclass,
					xfr->qtype);

			result = dns_message_gettempname(msg, &qname);
			if (result != ISC_R_SUCCESS)
				goto failure;
			dns_name_init(qname, NULL);
			isc_buffer_availableregion(&xfr->buf, &r);
			INSIST(r.length >= xfr->qname->length);
			r.length = xfr->qname->length;
			isc_buffer_putmem(&xfr->buf, xfr->qname->ndata,
					  xfr->qname->length);
			dns_name_fromregion(qname, &r);
			ISC_LIST_INIT(qname->list);
			ISC_LIST_APPEND(qname->list, qrdataset, link);

			dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
		} else {
			/*
			 * Reserve space for the 12-byte message header
			 */
			isc_buffer_add(&xfr->buf, 12);
			msg->tcp_continuation = 1;
		}
	}

	/*
	 * Try to fit in as many RRs as possible, unless "one-answer"
	 * format has been requested.
	 */
	for (n_rrs = 0; ; n_rrs++) {
		dns_name_t *name = NULL;
		isc_uint32_t ttl;
		dns_rdata_t *rdata = NULL;

		unsigned int size;
		isc_region_t r;

		msgname = NULL;
		msgrdata = NULL;
		msgrdl = NULL;
		msgrds = NULL;

		xfr->stream->methods->current(xfr->stream,
					      &name, &ttl, &rdata);
		size = name->length + 10 + rdata->length;
		isc_buffer_availableregion(&xfr->buf, &r);
		if (size >= r.length) {
			/*
			 * RR would not fit.  If there are other RRs in the
			 * buffer, send them now and leave this RR to the
			 * next message.  If this RR overflows the buffer
			 * all by itself, fail.
			 *
			 * In theory some RRs might fit in a TCP message
			 * when compressed even if they do not fit when
			 * uncompressed, but surely we don't want
			 * to send such monstrosities to an unsuspecting
			 * slave.
			 */
			if (n_rrs == 0) {
				xfrout_log(xfr, ISC_LOG_WARNING,
					   "RR too large for zone transfer "
					   "(%d bytes)", size);
				/* XXX DNS_R_RRTOOLARGE? */
				result = ISC_R_NOSPACE;
				goto failure;
			}
			break;
		}

		if (isc_log_wouldlog(ns_g_lctx, XFROUT_RR_LOGLEVEL))
			log_rr(name, rdata, ttl); /* XXX */

		result = dns_message_gettempname(msg, &msgname);
		if (result != ISC_R_SUCCESS)
			goto failure;
		dns_name_init(msgname, NULL);
		isc_buffer_availableregion(&xfr->buf, &r);
		INSIST(r.length >= name->length);
		r.length = name->length;
		isc_buffer_putmem(&xfr->buf, name->ndata, name->length);
		dns_name_fromregion(msgname, &r);

		/* Reserve space for RR header. */
		isc_buffer_add(&xfr->buf, 10);

		result = dns_message_gettemprdata(msg, &msgrdata);
		if (result != ISC_R_SUCCESS)
			goto failure;
		isc_buffer_availableregion(&xfr->buf, &r);
		r.length = rdata->length;
		isc_buffer_putmem(&xfr->buf, rdata->data, rdata->length);
		dns_rdata_init(msgrdata);
		dns_rdata_fromregion(msgrdata,
				     rdata->rdclass, rdata->type, &r);

		result = dns_message_gettemprdatalist(msg, &msgrdl);
		if (result != ISC_R_SUCCESS)
			goto failure;
		msgrdl->type = rdata->type;
		msgrdl->rdclass = rdata->rdclass;
		msgrdl->ttl = ttl;
		if (rdata->type == dns_rdatatype_sig ||
		    rdata->type == dns_rdatatype_rrsig)
			msgrdl->covers = dns_rdata_covers(rdata);
		else
			msgrdl->covers = dns_rdatatype_none;
		ISC_LIST_APPEND(msgrdl->rdata, msgrdata, link);

		result = dns_message_gettemprdataset(msg, &msgrds);
		if (result != ISC_R_SUCCESS)
			goto failure;
		result = dns_rdatalist_tordataset(msgrdl, msgrds);
		INSIST(result == ISC_R_SUCCESS);

		ISC_LIST_APPEND(msgname->list, msgrds, link);

		dns_message_addname(msg, msgname, DNS_SECTION_ANSWER);
		msgname = NULL;

		result = xfr->stream->methods->next(xfr->stream);
		if (result == ISC_R_NOMORE) {
			xfr->end_of_stream = ISC_TRUE;
			break;
		}
		CHECK(result);

		if (! xfr->many_answers)
			break;
		/*
		 * At this stage, at least 1 RR has been rendered into
		 * the message. Check if we want to clamp this message
		 * here (TCP only). 20480 was set as an upper limit to
		 * improve message compression.
		 */
		if ((isc_buffer_usedlength(&xfr->buf) >= 20480) && is_tcp)
			break;
	}

	if (is_tcp) {
		CHECK(dns_compress_init(&cctx, -1, xfr->mctx));
		dns_compress_setsensitive(&cctx, ISC_TRUE);
		cleanup_cctx = ISC_TRUE;
		CHECK(dns_message_renderbegin(msg, &cctx, &xfr->txbuf));
		CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0));
		CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0));
		CHECK(dns_message_renderend(msg));
		dns_compress_invalidate(&cctx);
		cleanup_cctx = ISC_FALSE;

		isc_buffer_usedregion(&xfr->txbuf, &used);
		isc_buffer_putuint16(&xfr->txlenbuf,
				     (isc_uint16_t)used.length);
		region.base = xfr->txlenbuf.base;
		region.length = 2 + used.length;
		xfrout_log(xfr, ISC_LOG_DEBUG(8),
			   "sending TCP message of %d bytes",
			   used.length);
		CHECK(isc_socket_send(xfr->client->tcpsocket, /* XXX */
				      &region, xfr->client->task,
				      xfrout_senddone,
				      xfr));
		xfr->sends++;
	} else {
		xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response");
		ns_client_send(xfr->client);
		xfr->stream->methods->pause(xfr->stream);
		xfrout_ctx_destroy(&xfr);
		return;
	}

	/* Advance lasttsig to be the last TSIG generated */
	CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig));

	xfr->nmsg++;

 failure:
	if (msgname != NULL) {
		if (msgrds != NULL) {
			if (dns_rdataset_isassociated(msgrds))
				dns_rdataset_disassociate(msgrds);
			dns_message_puttemprdataset(msg, &msgrds);
		}
		if (msgrdl != NULL) {
			ISC_LIST_UNLINK(msgrdl->rdata, msgrdata, link);
			dns_message_puttemprdatalist(msg, &msgrdl);
		}
		if (msgrdata != NULL)
			dns_message_puttemprdata(msg, &msgrdata);
		dns_message_puttempname(msg, &msgname);
	}

	if (tcpmsg != NULL)
		dns_message_destroy(&tcpmsg);

	if (cleanup_cctx)
		dns_compress_invalidate(&cctx);
	/*
	 * Make sure to release any locks held by database
	 * iterators before returning from the event handler.
	 */
	xfr->stream->methods->pause(xfr->stream);

	if (result == ISC_R_SUCCESS)
		return;

	xfrout_fail(xfr, result, "sending zone data");
}
Beispiel #30
0
int
main(int argc, char *argv[]) {
	dns_db_t *db;
	dns_dbnode_t *node;
	isc_result_t result;
	dns_name_t name;
	dns_offsets_t offsets;
	size_t len;
	isc_buffer_t source, target;
	char s[1000];
	char b[255];
	dns_rdataset_t rdataset, sigrdataset;
	int ch;
	dns_rdatatype_t type = 1;
	isc_boolean_t printnode = ISC_FALSE;
	isc_boolean_t addmode = ISC_FALSE;
	isc_boolean_t delmode = ISC_FALSE;
	isc_boolean_t holdmode = ISC_FALSE;
	isc_boolean_t verbose = ISC_FALSE;
	isc_boolean_t done = ISC_FALSE;
	isc_boolean_t quiet = ISC_FALSE;
	isc_boolean_t time_lookups = ISC_FALSE;
	isc_boolean_t found_as;
	isc_boolean_t find_zonecut = ISC_FALSE;
	isc_boolean_t noexact_zonecut = ISC_FALSE;
	int i, v;
	dns_rdatasetiter_t *rdsiter;
	char t1[256];
	char t2[256];
	isc_buffer_t tb1, tb2;
	isc_region_t r1, r2;
	dns_fixedname_t foundname;
	dns_name_t *fname;
	unsigned int options = 0, zcoptions;
	isc_time_t start, finish;
	char *origintext;
	dbinfo *dbi;
	dns_dbversion_t *version;
	dns_name_t *origin;
	size_t memory_quota = 0;
	dns_trust_t trust = 0;
	unsigned int addopts;
	isc_log_t *lctx = NULL;
	size_t n;

	dns_result_register();

	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
	RUNTIME_CHECK(dns_dbtable_create(mctx, dns_rdataclass_in, &dbtable) ==
		      ISC_R_SUCCESS);



	strcpy(dbtype, "rbt");
	while ((ch = isc_commandline_parse(argc, argv, "c:d:t:z:P:Q:glpqvT"))
	       != -1) {
		switch (ch) {
		case 'c':
			result = load(isc_commandline_argument, ".", ISC_TRUE);
			if (result != ISC_R_SUCCESS)
				printf("cache load(%s) %08x: %s\n",
				       isc_commandline_argument, result,
				       isc_result_totext(result));
			break;
		case 'd':
			n = strlcpy(dbtype, isc_commandline_argument,
				    sizeof(dbtype));
			if (n >= sizeof(dbtype)) {
				fprintf(stderr, "bad db type '%s'\n",
					isc_commandline_argument);
				exit(1);
			}
			break;
		case 'g':
			options |= (DNS_DBFIND_GLUEOK|DNS_DBFIND_VALIDATEGLUE);
			break;
		case 'l':
			RUNTIME_CHECK(isc_log_create(mctx, &lctx,
						     NULL) == ISC_R_SUCCESS);
			isc_log_setcontext(lctx);
			dns_log_init(lctx);
			dns_log_setcontext(lctx);
			break;
		case 'q':
			quiet = ISC_TRUE;
			verbose = ISC_FALSE;
			break;
		case 'p':
			printnode = ISC_TRUE;
			break;
		case 'P':
			pause_every = atoi(isc_commandline_argument);
			break;
		case 'Q':
			memory_quota = atoi(isc_commandline_argument);
			isc_mem_setquota(mctx, memory_quota);
			break;
		case 't':
			type = atoi(isc_commandline_argument);
			break;
		case 'T':
			time_lookups = ISC_TRUE;
			break;
		case 'v':
			verbose = ISC_TRUE;
			break;
		case 'z':
			origintext = strrchr(isc_commandline_argument, '/');
			if (origintext == NULL)
				origintext = isc_commandline_argument;
			else
				origintext++;	/* Skip '/'. */
			result = load(isc_commandline_argument, origintext,
				      ISC_FALSE);
			if (result != ISC_R_SUCCESS)
				printf("zone load(%s) %08x: %s\n",
				       isc_commandline_argument, result,
				       isc_result_totext(result));
			break;
		}
	}

	argc -= isc_commandline_index;
	argv += isc_commandline_index;
	POST(argv);

	if (argc != 0)
		printf("ignoring trailing arguments\n");

	/*
	 * Some final initialization...
	 */
	dns_fixedname_init(&foundname);
	fname = dns_fixedname_name(&foundname);
	dbi = NULL;
	origin = dns_rootname;
	version = NULL;

	if (time_lookups) {
		TIME_NOW(&start);
	}

	while (!done) {
		if (!quiet)
			printf("\n");
		if (fgets(s, sizeof(s), stdin) == NULL) {
			done = ISC_TRUE;
			continue;
		}
		len = strlen(s);
		if (len > 0U && s[len - 1] == '\n') {
			s[len - 1] = '\0';
			len--;
		}
		if (verbose && dbi != NULL) {
			if (dbi->wversion != NULL)
				printf("future version (%p)\n", dbi->wversion);
			for (i = 0; i < dbi->rcount; i++)
				if (dbi->rversions[i] != NULL)
					printf("open version %d (%p)\n", i,
					       dbi->rversions[i]);
		}
		dns_name_init(&name, offsets);
		if (strcmp(s, "!R") == 0) {
			DBI_CHECK(dbi);
			if (dbi->rcount == MAXVERSIONS) {
				printf("too many open versions\n");
				continue;
			}
			dns_db_currentversion(dbi->db,
					      &dbi->rversions[dbi->rcount]);
			printf("opened version %d\n", dbi->rcount);
			dbi->version = dbi->rversions[dbi->rcount];
			version = dbi->version;
			dbi->rcount++;
			continue;
		} else if (strcmp(s, "!W") == 0) {
			DBI_CHECK(dbi);
			if (dbi->wversion != NULL) {
				printf("using existing future version\n");
				dbi->version = dbi->wversion;
				version = dbi->version;
				continue;
			}
			result = dns_db_newversion(dbi->db, &dbi->wversion);
			if (result != ISC_R_SUCCESS)
				print_result("", result);
			else
				printf("newversion\n");
			dbi->version = dbi->wversion;
			version = dbi->version;
			continue;
		} else if (strcmp(s, "!C") == 0) {
			DBI_CHECK(dbi);
			addmode = ISC_FALSE;
			delmode = ISC_FALSE;
			if (dbi->version == NULL)
				continue;
			if (dbi->version == dbi->wversion) {
				printf("closing future version\n");
				dbi->wversion = NULL;
			} else {
				for (i = 0; i < dbi->rcount; i++) {
					if (dbi->version ==
					    dbi->rversions[i]) {
						dbi->rversions[i] = NULL;
					  printf("closing open version %d\n",
						 i);
						break;
					}
				}
			}
			dns_db_closeversion(dbi->db, &dbi->version, ISC_TRUE);
			version = NULL;
			continue;
		} else if (strcmp(s, "!X") == 0) {
			DBI_CHECK(dbi);
			addmode = ISC_FALSE;
			delmode = ISC_FALSE;
			if (dbi->version == NULL)
				continue;
			if (dbi->version == dbi->wversion) {
				printf("aborting future version\n");
				dbi->wversion = NULL;
			} else {
				for (i = 0; i < dbi->rcount; i++) {
					if (dbi->version ==
					    dbi->rversions[i]) {
						dbi->rversions[i] = NULL;
					  printf("closing open version %d\n",
						 i);
						break;
					}
				}
			}
			dns_db_closeversion(dbi->db, &dbi->version, ISC_FALSE);
			version = NULL;
			continue;
		} else if (strcmp(s, "!A") == 0) {
			DBI_CHECK(dbi);
			delmode = ISC_FALSE;
			if (addmode)
				addmode = ISC_FALSE;
			else
				addmode = ISC_TRUE;
			printf("addmode = %s\n", addmode ? "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!D") == 0) {
			DBI_CHECK(dbi);
			addmode = ISC_FALSE;
			if (delmode)
				delmode = ISC_FALSE;
			else
				delmode = ISC_TRUE;
			printf("delmode = %s\n", delmode ? "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!H") == 0) {
			DBI_CHECK(dbi);
			if (holdmode)
				holdmode = ISC_FALSE;
			else
				holdmode = ISC_TRUE;
			printf("holdmode = %s\n", holdmode ? "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!HR") == 0) {
			DBI_CHECK(dbi);
			for (i = 0; i < dbi->hold_count; i++)
				dns_db_detachnode(dbi->db,
						  &dbi->hold_nodes[i]);
			dbi->hold_count = 0;
			holdmode = ISC_FALSE;
			printf("held nodes have been detached\n");
			continue;
		} else if (strcmp(s, "!VC") == 0) {
			DBI_CHECK(dbi);
			printf("switching to current version\n");
			dbi->version = NULL;
			version = NULL;
			continue;
		} else if (strstr(s, "!V") == s) {
			DBI_CHECK(dbi);
			v = atoi(&s[2]);
			if (v >= dbi->rcount || v < 0) {
				printf("unknown open version %d\n", v);
				continue;
			}
			if (dbi->rversions[v] == NULL) {
				printf("version %d is not open\n", v);
				continue;
			}
			printf("switching to open version %d\n", v);
			dbi->version = dbi->rversions[v];
			version = dbi->version;
			continue;
		} else if (strstr(s, "!TR") == s) {
			trust = (unsigned int)atoi(&s[3]);
			printf("trust level is now %u\n", (unsigned int)trust);
			continue;
		} else if (strstr(s, "!T") == s) {
			type = (unsigned int)atoi(&s[2]);
			printf("now searching for type %u\n", type);
			continue;
		} else if (strcmp(s, "!G") == 0) {
			if ((options & DNS_DBFIND_GLUEOK) != 0)
				options &= ~DNS_DBFIND_GLUEOK;
			else
				options |= DNS_DBFIND_GLUEOK;
			printf("glue ok = %s\n",
			       ((options & DNS_DBFIND_GLUEOK) != 0) ?
			       "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!GV") == 0) {
			if ((options & DNS_DBFIND_VALIDATEGLUE) != 0)
				options &= ~DNS_DBFIND_VALIDATEGLUE;
			else
				options |= DNS_DBFIND_VALIDATEGLUE;
			printf("validate glue = %s\n",
			       ((options & DNS_DBFIND_VALIDATEGLUE) != 0) ?
			       "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!WC") == 0) {
			if ((options & DNS_DBFIND_NOWILD) != 0)
				options &= ~DNS_DBFIND_NOWILD;
			else
				options |= DNS_DBFIND_NOWILD;
			printf("wildcard matching = %s\n",
			       ((options & DNS_DBFIND_NOWILD) == 0) ?
			       "TRUE" : "FALSE");
			continue;
		} else if (strstr(s, "!LS ") == s) {
			DBI_CHECK(dbi);
			list(dbi, &s[4]);
			continue;
		} else if (strcmp(s, "!LS") == 0) {
			DBI_CHECK(dbi);
			list(dbi, NULL);
			continue;
		} else if (strstr(s, "!DU ") == s) {
			DBI_CHECK(dbi);
			result = dns_db_dump(dbi->db, dbi->version, s+4);
			if (result != ISC_R_SUCCESS) {
				printf("\n");
				print_result("", result);
			}
			continue;
		} else if (strcmp(s, "!PN") == 0) {
			if (printnode)
				printnode = ISC_FALSE;
			else
				printnode = ISC_TRUE;
			printf("printnode = %s\n",
			       printnode ? "TRUE" : "FALSE");
			continue;
		} else if (strstr(s, "!P") == s) {
			DBI_CHECK(dbi);
			v = atoi(&s[2]);
			dbi->pause_every = v;
			continue;
		} else if (strcmp(s, "!+") == 0) {
			DBI_CHECK(dbi);
			dbi->ascending = ISC_TRUE;
			continue;
		} else if (strcmp(s, "!-") == 0) {
			DBI_CHECK(dbi);
			dbi->ascending = ISC_FALSE;
			continue;
		} else if (strcmp(s, "!DB") == 0) {
			dbi = NULL;
			origin = dns_rootname;
			version = NULL;
			printf("now searching all databases\n");
			continue;
		} else if (strncmp(s, "!DB ", 4) == 0) {
			dbi = select_db(s+4);
			if (dbi != NULL) {
				db = dbi->db;
				origin = dns_db_origin(dbi->db);
				version = dbi->version;
				addmode = ISC_FALSE;
				delmode = ISC_FALSE;
				holdmode = ISC_FALSE;
			} else {
				db = NULL;
				version = NULL;
				origin = dns_rootname;
				printf("database not found; "
				       "now searching all databases\n");
			}
			continue;
		} else if (strcmp(s, "!ZC") == 0) {
			if (find_zonecut)
				find_zonecut = ISC_FALSE;
			else
				find_zonecut = ISC_TRUE;
			printf("find_zonecut = %s\n",
			       find_zonecut ? "TRUE" : "FALSE");
			continue;
		} else if (strcmp(s, "!NZ") == 0) {
			if (noexact_zonecut)
				noexact_zonecut = ISC_FALSE;
			else
				noexact_zonecut = ISC_TRUE;
			printf("noexact_zonecut = %s\n",
			       noexact_zonecut ? "TRUE" : "FALSE");
			continue;
		}

		isc_buffer_init(&source, s, len);
		isc_buffer_add(&source, len);
		isc_buffer_init(&target, b, sizeof(b));
		result = dns_name_fromtext(&name, &source, origin, 0, &target);
		if (result != ISC_R_SUCCESS) {
			print_result("bad name: ", result);
			continue;
		}

		if (dbi == NULL) {
			zcoptions = 0;
			if (noexact_zonecut)
				zcoptions |= DNS_DBTABLEFIND_NOEXACT;
			db = NULL;
			result = dns_dbtable_find(dbtable, &name, zcoptions,
						  &db);
			if (result != ISC_R_SUCCESS &&
			    result != DNS_R_PARTIALMATCH) {
				if (!quiet) {
					printf("\n");
					print_result("", result);
				}
				continue;
			}
			isc_buffer_init(&tb1, t1, sizeof(t1));
			result = dns_name_totext(dns_db_origin(db), ISC_FALSE,
						 &tb1);
			if (result != ISC_R_SUCCESS) {
				printf("\n");
				print_result("", result);
				dns_db_detach(&db);
				continue;
			}
			isc_buffer_usedregion(&tb1, &r1);
			printf("\ndatabase = %.*s (%s)\n",
			       (int)r1.length, r1.base,
			       (dns_db_iszone(db)) ? "zone" : "cache");
		}
		node = NULL;
		dns_rdataset_init(&rdataset);
		dns_rdataset_init(&sigrdataset);

		if (find_zonecut && dns_db_iscache(db)) {
			zcoptions = options;
			if (noexact_zonecut)
				zcoptions |= DNS_DBFIND_NOEXACT;
			result = dns_db_findzonecut(db, &name, zcoptions,
						    0, &node, fname,
						    &rdataset, &sigrdataset);
		} else {
			result = dns_db_find(db, &name, version, type,
					     options, 0, &node, fname,
					     &rdataset, &sigrdataset);
		}

		if (!quiet) {
			if (dbi != NULL)
				printf("\n");
			print_result("", result);
		}

		found_as = ISC_FALSE;
		switch (result) {
		case ISC_R_SUCCESS:
		case DNS_R_GLUE:
		case DNS_R_CNAME:
		case DNS_R_ZONECUT:
			break;
		case DNS_R_DNAME:
		case DNS_R_DELEGATION:
			found_as = ISC_TRUE;
			break;
		case DNS_R_NXRRSET:
			if (dns_rdataset_isassociated(&rdataset))
				break;
			if (dbi != NULL) {
				if (holdmode) {
					RUNTIME_CHECK(dbi->hold_count <
						      MAXHOLD);
					dbi->hold_nodes[dbi->hold_count++] =
						node;
					node = NULL;
				} else
					dns_db_detachnode(db, &node);
			} else {
				dns_db_detachnode(db, &node);
				dns_db_detach(&db);
			}
			continue;
		case DNS_R_NXDOMAIN:
			if (dns_rdataset_isassociated(&rdataset))
				break;
			/* FALLTHROUGH */
		default:
			if (dbi == NULL)
				dns_db_detach(&db);
			if (quiet)
				print_result("", result);
			continue;
		}
		if (found_as && !quiet) {
			isc_buffer_init(&tb1, t1, sizeof(t1));
			isc_buffer_init(&tb2, t2, sizeof(t2));
			result = dns_name_totext(&name, ISC_FALSE, &tb1);
			if (result != ISC_R_SUCCESS) {
				print_result("", result);
				dns_db_detachnode(db, &node);
				if (dbi == NULL)
					dns_db_detach(&db);
				continue;
			}
			result = dns_name_totext(fname, ISC_FALSE, &tb2);
			if (result != ISC_R_SUCCESS) {
				print_result("", result);
				dns_db_detachnode(db, &node);
				if (dbi == NULL)
					dns_db_detach(&db);
				continue;
			}
			isc_buffer_usedregion(&tb1, &r1);
			isc_buffer_usedregion(&tb2, &r2);
			printf("found %.*s as %.*s\n",
			       (int)r1.length, r1.base,
			       (int)r2.length, r2.base);
		}

		if (printnode)
			dns_db_printnode(db, node, stdout);

		if (!found_as && type == dns_rdatatype_any) {
			rdsiter = NULL;
			result = dns_db_allrdatasets(db, node, version, 0,
						     &rdsiter);
			if (result == ISC_R_SUCCESS) {
				if (!quiet)
					print_rdatasets(fname, rdsiter);
				dns_rdatasetiter_destroy(&rdsiter);
			} else
				print_result("", result);
		} else {
			if (!quiet)
				print_rdataset(fname, &rdataset);
			if (dns_rdataset_isassociated(&sigrdataset)) {
				if (!quiet)
					print_rdataset(fname, &sigrdataset);
				dns_rdataset_disassociate(&sigrdataset);
			}
			if (dbi != NULL && addmode && !found_as) {
				rdataset.ttl++;
				rdataset.trust = trust;
				if (dns_db_iszone(db))
					addopts = DNS_DBADD_MERGE;
				else
					addopts = 0;
				result = dns_db_addrdataset(db, node, version,
							    0, &rdataset,
							    addopts, NULL);
				if (result != ISC_R_SUCCESS)
					print_result("", result);
				if (printnode)
					dns_db_printnode(db, node, stdout);
			} else if (dbi != NULL && delmode && !found_as) {
				result = dns_db_deleterdataset(db, node,
							       version, type,
							       0);
				if (result != ISC_R_SUCCESS)
					print_result("", result);
				if (printnode)
					dns_db_printnode(db, node, stdout);
			}
			dns_rdataset_disassociate(&rdataset);
		}

		if (dbi != NULL) {
			if (holdmode) {
				RUNTIME_CHECK(dbi->hold_count < MAXHOLD);
				dbi->hold_nodes[dbi->hold_count++] = node;
				node = NULL;
			} else
				dns_db_detachnode(db, &node);
		} else {
			dns_db_detachnode(db, &node);
			dns_db_detach(&db);
		}
	}

	if (time_lookups) {
		isc_uint64_t usec;

		TIME_NOW(&finish);

		usec = isc_time_microdiff(&finish, &start);

		printf("elapsed time: %lu.%06lu seconds\n",
		       (unsigned long)(usec / 1000000),
		       (unsigned long)(usec % 1000000));
	}

	unload_all();

	dns_dbtable_detach(&dbtable);

	if (lctx != NULL)
		isc_log_destroy(&lctx);

	if (!quiet)
		isc_mem_stats(mctx, stdout);

	return (0);
}