/* res_nsendsigned */
int
res_nsendsigned(res_state statp, const u_char *msg, int msglen,
		ns_tsig_key *key, u_char *answer, int anslen)
{
	res_state nstatp;
	DST_KEY *dstkey;
	int usingTCP = 0;
	u_char *newmsg;
	int newmsglen, bufsize, siglen;
	u_char sig[64];
	HEADER *hp;
	time_t tsig_time;
	int ret;

	dst_init();

	nstatp = (res_state) malloc(sizeof(*statp));
	if (nstatp == NULL) {
		errno = ENOMEM;
		return (-1);
	}
	memcpy(nstatp, statp, sizeof(*statp));

	bufsize = msglen + 1024;
	newmsg = (u_char *) malloc(bufsize);
	if (newmsg == NULL) {
		errno = ENOMEM;
		return (-1);
	}
	memcpy(newmsg, msg, msglen);
	newmsglen = msglen;

	if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1)
		dstkey = NULL;
	else
		dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
					   NS_KEY_TYPE_AUTH_ONLY,
					   NS_KEY_PROT_ANY,
					   key->data, key->len);
	if (dstkey == NULL) {
		errno = EINVAL;
		free(nstatp);
		free(newmsg);
		return (-1);
	}

	nstatp->nscount = 1;
	siglen = sizeof(sig);
	ret = ns_sign(newmsg, &newmsglen, bufsize, ns_r_noerror, dstkey, NULL, 0,
		      sig, &siglen, 0);
	if (ret < 0) {
		free (nstatp);
		free (newmsg);
		dst_free_key(dstkey);
		if (ret == NS_TSIG_ERROR_NO_SPACE)
			errno  = EMSGSIZE;
		else if (ret == -1)
			errno  = EINVAL;
		return (ret);
	}

	if (newmsglen > NS_PACKETSZ || (nstatp->options & RES_IGNTC))
		usingTCP = 1;
	if (usingTCP == 0)
		nstatp->options |= RES_IGNTC;
	else
		nstatp->options |= RES_USEVC;

retry:

	ret = res_nsend(nstatp, newmsg, newmsglen, answer, anslen);
	if (ret < 0) {
		free (nstatp);
		free (newmsg);
		dst_free_key(dstkey);
		return (ret);
	}

	anslen = ret;
	ret = ns_verify(answer, &anslen, dstkey, sig, siglen,
			NULL, NULL, &tsig_time, nstatp->options & RES_KEEPTSIG);
	if (ret != 0) {
		Dprint(nstatp->pfcode & RES_PRF_REPLY,
		       (stdout, ";; TSIG invalid (%s)\n", p_rcode(ret)));
		free (nstatp);
		free (newmsg);
		dst_free_key(dstkey);
		if (ret == -1)
			errno = EINVAL;
		else
			errno = ENOTTY;
		return (-1);
	}
	Dprint(nstatp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n"));

	hp = (HEADER *) answer;
	if (hp->tc && usingTCP == 0) {
		nstatp->options &= ~RES_IGNTC;
		usingTCP = 1;
		goto retry;
	}

	free (nstatp);
	free (newmsg);
	dst_free_key(dstkey);
	return (anslen);
}
Beispiel #2
0
static DST_KEY *
dst_s_read_public_key(const char *in_name, const u_int16_t in_id, int in_alg)
{
	int flags, proto, alg, len, dlen;
	int c;
	char name[PATH_MAX], enckey[RAW_KEY_SIZE], *notspace;
	u_char deckey[RAW_KEY_SIZE];
	FILE *fp;

	if (in_name == NULL) {
		EREPORT(("dst_read_public_key(): No key name given\n"));
		return (NULL);
	}
	if (dst_s_build_filename(name, in_name, in_id, in_alg, PUBLIC_KEY,
				 PATH_MAX) == -1) {
		EREPORT(("dst_read_public_key(): Cannot make filename from %s, %d, and %s\n",
			 in_name, in_id, PUBLIC_KEY));
		return (NULL);
	}
	/*
	 * Open the file and read it's formatted contents up to key
	 * File format:
	 *    domain.name [ttl] [IN] KEY  &lt;flags&gt; &lt;protocol&gt; &lt;algorithm&gt; &lt;key&gt;
	 * flags, proto, alg stored as decimal (or hex numbers FIXME).
	 * (FIXME: handle parentheses for line continuation.)
	 */
	if ((fp = dst_s_fopen(name, "r", 0)) == NULL) {
		EREPORT(("dst_read_public_key(): Public Key not found %s\n",
			 name));
		return (NULL);
	}
	/* Skip domain name, which ends at first blank */
	while ((c = getc(fp)) != EOF)
		if (isspace(c))
			break;
	/* Skip blank to get to next field */
	while ((c = getc(fp)) != EOF)
		if (!isspace(c))
			break;

	/* Skip optional TTL -- if initial digit, skip whole word. */
	if (isdigit(c)) {
		while ((c = getc(fp)) != EOF)
			if (isspace(c))
				break;
		while ((c = getc(fp)) != EOF)
			if (!isspace(c))
				break;
	}
	/* Skip optional "IN" */
	if (c == 'I' || c == 'i') {
		while ((c = getc(fp)) != EOF)
			if (isspace(c))
				break;
		while ((c = getc(fp)) != EOF)
			if (!isspace(c))
				break;
	}
	/* Locate and skip "KEY" */
	if (c != 'K' && c != 'k') {
		EREPORT(("\"KEY\" doesn't appear in file: %s", name));
		return NULL;
	}
	while ((c = getc(fp)) != EOF)
		if (isspace(c))
			break;
	while ((c = getc(fp)) != EOF)
		if (!isspace(c))
			break;
	ungetc(c, fp);		/*%< return the charcter to the input field */
	/* Handle hex!! FIXME.  */

	if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) {
		EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n"
			 ,name));
		return (NULL);
	}
	/* read in the key string */
	fgets(enckey, sizeof(enckey), fp);

	/* If we aren't at end-of-file, something is wrong.  */
	while ((c = getc(fp)) != EOF)
		if (!isspace(c))
			break;
	if (!feof(fp)) {
		EREPORT(("Key too long in file: %s", name));
		return NULL;
	}
	fclose(fp);

	if ((len = strlen(enckey)) <= 0)
		return (NULL);

	/* discard \n */
	enckey[--len] = '\0';

	/* remove leading spaces */
	for (notspace = (char *) enckey; isspace((*notspace)&0xff); len--)
		notspace++;

	dlen = b64_pton(notspace, deckey, sizeof(deckey));
	if (dlen < 0) {
		EREPORT(("dst_read_public_key: bad return from b64_pton = %d",
			 dlen));
		return (NULL);
	}
	/* store key and info in a key structure that is returned */
/*	return dst_store_public_key(in_name, alg, proto, 666, flags, deckey,
				    dlen);*/
	return dst_buffer_to_key(in_name, alg, flags, proto, deckey, dlen);
}
Beispiel #3
0
/*% res_nsendsigned */
int
res_nsendsigned(res_state statp, const u_char *msg, int msglen,
		ns_tsig_key *key, u_char *answer, int anslen)
{
	res_state nstatp;
	DST_KEY *dstkey;
	int usingTCP = 0;
	u_char *newmsg;
	int newmsglen, bufsize, siglen;
	u_char sig[64];
	HEADER *hp;
	time_t tsig_time;
	int ret;
	int len;

	dst_init();

	nstatp = (res_state) malloc(sizeof(*statp));
	if (nstatp == NULL) {
		errno = ENOMEM;
		return (-1);
	}
	memcpy(nstatp, statp, sizeof(*statp));

	bufsize = msglen + 1024;
	newmsg = (u_char *) malloc(bufsize);
	if (newmsg == NULL) {
		free(nstatp);
		errno = ENOMEM;
		return (-1);
	}
	memcpy(newmsg, msg, msglen);
	newmsglen = msglen;

	if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1)
		dstkey = NULL;
	else
		dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
					   NS_KEY_TYPE_AUTH_ONLY,
					   NS_KEY_PROT_ANY,
					   key->data, key->len);
	if (dstkey == NULL) {
		errno = EINVAL;
		free(nstatp);
		free(newmsg);
		return (-1);
	}

	nstatp->nscount = 1;
	siglen = sizeof(sig);
	ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0,
		      sig, &siglen, 0);
	if (ret < 0) {
		free (nstatp);
		free (newmsg);
		dst_free_key(dstkey);
		if (ret == NS_TSIG_ERROR_NO_SPACE)
			errno  = EMSGSIZE;
		else if (ret == -1)
			errno  = EINVAL;
		return (ret);
	}

	if (newmsglen > PACKETSZ || nstatp->options & RES_USEVC)
		usingTCP = 1;
	if (usingTCP == 0)
		nstatp->options |= RES_IGNTC;
	else
		nstatp->options |= RES_USEVC;
	/*
	 * Stop res_send printing the answer.
	 */
	nstatp->options &= ~RES_DEBUG;
	nstatp->pfcode &= ~RES_PRF_REPLY;

retry:

	len = res_nsend(nstatp, newmsg, newmsglen, answer, anslen);
	if (len < 0) {
		free (nstatp);
		free (newmsg);
		dst_free_key(dstkey);
		return (len);
	}

	ret = ns_verify(answer, &len, dstkey, sig, siglen,
			NULL, NULL, &tsig_time, nstatp->options & RES_KEEPTSIG);
	if (ret != 0) {
		Dprint((statp->options & RES_DEBUG) ||
		       ((statp->pfcode & RES_PRF_REPLY) &&
			(statp->pfcode & RES_PRF_HEAD1)),
		       (stdout, ";; got answer:\n"));

		DprintQ((statp->options & RES_DEBUG) ||
			(statp->pfcode & RES_PRF_REPLY),
			(stdout, "%s", ""),
			answer, (anslen > len) ? len : anslen);

		if (ret > 0) {
			Dprint(statp->pfcode & RES_PRF_REPLY,
			       (stdout, ";; server rejected TSIG (%s)\n",
				p_rcode(ret)));
		} else {
			Dprint(statp->pfcode & RES_PRF_REPLY,
			       (stdout, ";; TSIG invalid (%s)\n",
				p_rcode(-ret)));
		}

		free (nstatp);
		free (newmsg);
		dst_free_key(dstkey);
		if (ret == -1)
			errno = EINVAL;
		else
			errno = ENOTTY;
		return (-1);
	}

	hp = (HEADER *) answer;
	if (hp->tc && !usingTCP && (statp->options & RES_IGNTC) == 0U) {
		nstatp->options &= ~RES_IGNTC;
		usingTCP = 1;
		goto retry;
	}
	Dprint((statp->options & RES_DEBUG) ||
	       ((statp->pfcode & RES_PRF_REPLY) &&
		(statp->pfcode & RES_PRF_HEAD1)),
	       (stdout, ";; got answer:\n"));

	DprintQ((statp->options & RES_DEBUG) ||
		(statp->pfcode & RES_PRF_REPLY),
		(stdout, "%s", ""),
		answer, (anslen > len) ? len : anslen);

	Dprint(statp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n"));

	free (nstatp);
	free (newmsg);
	dst_free_key(dstkey);
	return (len);
}
Beispiel #4
0
static int
printZone(ns_type xfr, const char *zone, const struct sockaddr_in *sin,
	  ns_tsig_key *key)
{
	static u_char *answer = NULL;
	static int answerLen = 0;

	querybuf buf;
	int msglen, amtToRead, numRead, result, sockFD, len;
	int count, type, rlen, done, n;
	int numAnswers, numRecords, soacnt;
	u_char *cp, tmp[NS_INT16SZ];
	char dname[2][NS_MAXDNAME];
	enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING }
		error;
	pid_t zpid = -1;
	u_char *newmsg;
	int newmsglen;
	ns_tcp_tsig_state tsig_state;
	int tsig_ret, tsig_required, tsig_present;

	switch (xfr) {
	case ns_t_axfr:
	case ns_t_zxfr:
		break;
	default:
		fprintf(stderr, ";; %s - transfer type not supported\n",
			p_type(xfr));
		return (ERROR);
	}

	/*
	 *  Create a query packet for the requested zone name.
	 */
	msglen = res_nmkquery(&res, ns_o_query, zone,
			      queryClass, ns_t_axfr, NULL,
			      0, 0, buf.qb2, sizeof buf);
	if (msglen < 0) {
		if (res.options & RES_DEBUG)
			fprintf(stderr, ";; res_nmkquery failed\n");
		return (ERROR);
	}

	/*
	 * Sign the message if a key was sent
	 */
	if (key == NULL) {
		newmsg = (u_char *)&buf;
		newmsglen = msglen;
	} else {
		DST_KEY *dstkey;
		int bufsize, siglen;
		u_char sig[64];
		int ret;
		
		/* ns_sign() also calls dst_init(), but there is no harm
		 * doing it twice
		 */
		dst_init();
		
		bufsize = msglen + 1024;
		newmsg = (u_char *) malloc(bufsize);
		if (newmsg == NULL) {
			errno = ENOMEM;
			return (-1);
		}
		memcpy(newmsg, (u_char *)&buf, msglen);
		newmsglen = msglen;
		
		if (strcmp(key->alg, NS_TSIG_ALG_HMAC_MD5) != 0)
			dstkey = NULL;
		else
			dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
							NS_KEY_TYPE_AUTH_ONLY,
							NS_KEY_PROT_ANY,
							key->data, key->len);
		if (dstkey == NULL) {
			errno = EINVAL;
			if (key)
				free(newmsg);
			return (-1);
		}
		
		siglen = sizeof(sig);
/* newmsglen++; */
		ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0,
		      sig, &siglen, 0);
		if (ret < 0) {
			if (key)
				free (newmsg);
			if (ret == NS_TSIG_ERROR_NO_SPACE)
				errno  = EMSGSIZE;
			else if (ret == -1)
				errno  = EINVAL;
			return (ret);
		}
		ns_verify_tcp_init(dstkey, sig, siglen, &tsig_state);
	}

	/*
	 *  Set up a virtual circuit to the server.
	 */
	if ((sockFD = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) {
		int e = errno;

		perror(";; socket");
		return (e);
	}
	
	switch (sin->sin_family) {
	case AF_INET:
		if (bind(sockFD, (struct sockaddr *)&myaddress,
			 sizeof myaddress) < 0){
			int e = errno;

			fprintf(stderr, ";; bind(%s port %u): %s\n",
				inet_ntoa(myaddress.sin_addr),
				ntohs(myaddress.sin_port),
				strerror(e));
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		}
		if (connect(sockFD, (const struct sockaddr *)sin,
			    sizeof *sin) < 0) {
			int e = errno;

			perror(";; connect");
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		}
		break;
	case AF_INET6:
		if (bind(sockFD, (struct sockaddr *)&myaddress6,
			 sizeof myaddress6) < 0){
			int e = errno;
			char buf[80];

			fprintf(stderr, ";; bind(%s port %u): %s\n",
				inet_ntop(AF_INET6, &myaddress6.sin6_addr,
					  buf, sizeof(buf)),
				ntohs(myaddress6.sin6_port),
				strerror(e));
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		}
		if (connect(sockFD, (const struct sockaddr *)sin,
			    sizeof(struct sockaddr_in6)) < 0) {
			int e = errno;

			perror(";; connect");
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		}
		break;
	}

	/*
	 * Send length & message for zone transfer
	 */

	ns_put16(newmsglen, tmp);
        if (write(sockFD, (char *)tmp, NS_INT16SZ) != NS_INT16SZ ||
            write(sockFD, (char *)newmsg, newmsglen) != newmsglen) {
		int e = errno;
		if (key)
			free (newmsg);
		perror(";; write");
		(void) close(sockFD);
		sockFD = -1;
		return (e);
	} else if (key)
		free (newmsg);

	/*
	 * If we're compressing, push a gzip into the pipeline.
	 */
	if (xfr == ns_t_zxfr) {
		enum { rd = 0, wr = 1 };
		int z[2];

		if (pipe(z) < 0) {
			int e = errno;

			perror(";; pipe");
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		}
		zpid = vfork();
		if (zpid < 0) {
			int e = errno;

			perror(";; fork");
			(void) close(sockFD);
			sockFD = -1;
			return (e);
		} else if (zpid == 0) {
			/* Child. */
			(void) close(z[rd]);
			(void) dup2(sockFD, STDIN_FILENO);
			(void) close(sockFD);
			(void) dup2(z[wr], STDOUT_FILENO);
			(void) close(z[wr]);
			execlp("gzip", "gzip", "-d", "-v", NULL);
			perror(";; child: execlp(gunzip)");
			_exit(1);
		}
		/* Parent. */
		(void) close(z[wr]);
		(void) dup2(z[rd], sockFD);
		(void) close(z[rd]);
	}
	result = 0;
	numAnswers = 0;
	numRecords = 0;
	soacnt = 0;
	error = NO_ERRORS;
	numRead = 0;

	dname[0][0] = '\0';
	for (done = 0; !done; (void)NULL) {
		/*
		 * Read the length of the response.
		 */

		cp = tmp;
		amtToRead = INT16SZ;
		while (amtToRead > 0 &&
		   (numRead = read(sockFD, cp, amtToRead)) > 0) {
			cp += numRead;
			amtToRead -= numRead;
		}
		if (numRead <= 0) {
			error = ERR_READING_LEN;
			break;
		}

		len = ns_get16(tmp);
		if (len == 0)
			break;	/* nothing left to read */

		/*
		 * The server sent too much data to fit the existing buffer --
		 * allocate a new one.
		 */
		if (len > answerLen) {
			if (answerLen != 0)
				free(answer);
			answerLen = len;
			answer = (u_char *)malloc(answerLen);
		}

		/*
		 * Read the response.
		 */

		amtToRead = len;
		cp = answer;
		while (amtToRead > 0 &&
		       (numRead = read(sockFD, cp, amtToRead)) > 0) {
			cp += numRead;
			amtToRead -= numRead;
		}
		if (numRead <= 0) {
			error = ERR_READING_MSG;
			break;
		}

		result = print_axfr(stdout, answer, len);
		if (result != 0) {
			error = ERR_PRINTING;
			break;
		}
		numRecords += htons(((HEADER *)answer)->ancount);
		numAnswers++;

		/* Header. */
		cp = answer + HFIXEDSZ;
		/* Question. */
		for (count = ntohs(((HEADER *)answer)->qdcount);	
		     count > 0;
		     count--) {
			n = dn_skipname(cp, answer + len);
			if (n < 0) {
				error = ERR_PRINTING;
				done++;
				break;
			}
			cp += n + QFIXEDSZ;
			if (cp > answer + len) {
				error = ERR_PRINTING;
				done++;
				break;
			}
		}
		/* Answer. */
		for (count = ntohs(((HEADER *)answer)->ancount);
		     count > 0 && !done;
		     count--) {
			n = dn_expand(answer, answer + len, cp,
				      dname[soacnt], sizeof dname[0]);
			if (n < 0) {
				error = ERR_PRINTING;
				done++;
				break;
			}
			cp += n;
			if (cp + 3 * INT16SZ + INT32SZ > answer + len) {
				error = ERR_PRINTING;
				done++;
				break;
			}
			GETSHORT(type, cp);
			cp += INT16SZ;
			cp += INT32SZ;	/* ttl */
			GETSHORT(rlen, cp);
			cp += rlen;
			if (cp > answer + len) {
				error = ERR_PRINTING;
				done++;
				break;
			}
			if (type == T_SOA && soacnt++ &&
			    ns_samename(dname[0], dname[1]) == 1) {
				done++;
				break;
			}
		}

		/*
		 * Verify the TSIG
		 */

		if (key) {
			if (ns_find_tsig(answer, answer + len) != NULL)
				tsig_present = 1;
			else
				tsig_present = 0;
			if (numAnswers == 1 || soacnt > 1)
				tsig_required = 1;
			else
				tsig_required = 0;
			tsig_ret = ns_verify_tcp(answer, &len, &tsig_state,
						 tsig_required);
			if (tsig_ret == 0) {
				if (tsig_present)
					printf("; TSIG ok\n");
			}
			else
				printf("; TSIG invalid\n");
		}

	}

	printf(";; Received %d answer%s (%d record%s).\n",
	       numAnswers, (numAnswers != 1) ? "s" : "",
	       numRecords, (numRecords != 1) ? "s" : "");

	(void) close(sockFD);
	sockFD = -1;

	/*
	 * If we were uncompressing, reap the uncompressor.
	 */
	if (xfr == ns_t_zxfr) {
		pid_t pid;
		int status = 0;

		pid = wait(&status);
		if (pid < 0) {
			int e = errno;

			perror(";; wait");
			return (e);
		}
		if (pid != zpid) {
			fprintf(stderr, ";; wrong pid (%lu != %lu)\n",
				(u_long)pid, (u_long)zpid);
			return (ERROR);
		}
		printf(";; pid %lu: exit %d, signal %d, core %c\n",
		       (u_long)pid, WEXITSTATUS(status),
		       WIFSIGNALED(status) ? WTERMSIG(status) : 0,
		       WCOREDUMP(status) ? 't' : 'f');
	}

	switch (error) {
	case NO_ERRORS:
		return (0);

	case ERR_READING_LEN:
		return (EMSGSIZE);

	case ERR_PRINTING:
		return (result);

	case ERR_READING_MSG:
		return (EMSGSIZE);

	default:
		return (EFAULT);
	}
}