1#include "port_before.h"
2#include "fd_setsize.h"
3
4#include <sys/types.h>
5#include <sys/param.h>
6
7#include <netinet/in.h>
8#include <arpa/nameser.h>
9#include <arpa/inet.h>
10
11#include <isc/dst.h>
12
13#include <errno.h>
14#include <netdb.h>
15#include <resolv.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
20
21#include "port_after.h"
22
23//#define DEBUG
24#include "res_debug.h"
25
26
27/*% res_nsendsigned */
28int
29res_nsendsigned(res_state statp, const u_char *msg, int msglen,
30		ns_tsig_key *key, u_char *answer, int anslen)
31{
32	res_state nstatp;
33	DST_KEY *dstkey;
34	int usingTCP = 0;
35	u_char *newmsg;
36	int newmsglen, bufsize, siglen;
37	u_char sig[64];
38	HEADER *hp;
39	time_t tsig_time;
40	int ret;
41	int len;
42
43	dst_init();
44
45	nstatp = (res_state) malloc(sizeof(*statp));
46	if (nstatp == NULL) {
47		errno = ENOMEM;
48		return (-1);
49	}
50	memcpy(nstatp, statp, sizeof(*statp));
51
52	bufsize = msglen + 1024;
53	newmsg = (u_char *) malloc(bufsize);
54	if (newmsg == NULL) {
55		free(nstatp);
56		errno = ENOMEM;
57		return (-1);
58	}
59	memcpy(newmsg, msg, msglen);
60	newmsglen = msglen;
61
62	if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1)
63		dstkey = NULL;
64	else
65		dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
66					   NS_KEY_TYPE_AUTH_ONLY,
67					   NS_KEY_PROT_ANY,
68					   key->data, key->len);
69	if (dstkey == NULL) {
70		errno = EINVAL;
71		free(nstatp);
72		free(newmsg);
73		return (-1);
74	}
75
76	nstatp->nscount = 1;
77	siglen = sizeof(sig);
78	ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0,
79		      sig, &siglen, 0);
80	if (ret < 0) {
81		free (nstatp);
82		free (newmsg);
83		dst_free_key(dstkey);
84		if (ret == NS_TSIG_ERROR_NO_SPACE)
85			errno  = EMSGSIZE;
86		else if (ret == -1)
87			errno  = EINVAL;
88		return (ret);
89	}
90
91	if (newmsglen > PACKETSZ || nstatp->options & RES_USEVC)
92		usingTCP = 1;
93	if (usingTCP == 0)
94		nstatp->options |= RES_IGNTC;
95	else
96		nstatp->options |= RES_USEVC;
97	/*
98	 * Stop res_send printing the answer.
99	 */
100	nstatp->options &= ~RES_DEBUG;
101	nstatp->pfcode &= ~RES_PRF_REPLY;
102
103retry:
104
105	len = res_nsend(nstatp, newmsg, newmsglen, answer, anslen);
106	if (len < 0) {
107		free (nstatp);
108		free (newmsg);
109		dst_free_key(dstkey);
110		return (len);
111	}
112
113	ret = ns_verify(answer, &len, dstkey, sig, siglen,
114			NULL, NULL, &tsig_time, nstatp->options & RES_KEEPTSIG);
115	if (ret != 0) {
116		Dprint((statp->options & RES_DEBUG) ||
117		       ((statp->pfcode & RES_PRF_REPLY) &&
118			(statp->pfcode & RES_PRF_HEAD1)),
119		       (stdout, ";; got answer:\n"));
120
121		DprintQ((statp->options & RES_DEBUG) ||
122			(statp->pfcode & RES_PRF_REPLY),
123			(stdout, "%s", ""),
124			answer, (anslen > len) ? len : anslen);
125
126		if (ret > 0) {
127			Dprint(statp->pfcode & RES_PRF_REPLY,
128			       (stdout, ";; server rejected TSIG (%s)\n",
129				p_rcode(ret)));
130		} else {
131			Dprint(statp->pfcode & RES_PRF_REPLY,
132			       (stdout, ";; TSIG invalid (%s)\n",
133				p_rcode(-ret)));
134		}
135
136		free (nstatp);
137		free (newmsg);
138		dst_free_key(dstkey);
139		if (ret == -1)
140			errno = EINVAL;
141		else
142			errno = ENOTTY;
143		return (-1);
144	}
145
146	hp = (HEADER *) answer;
147	if (hp->tc && !usingTCP && (statp->options & RES_IGNTC) == 0U) {
148		nstatp->options &= ~RES_IGNTC;
149		usingTCP = 1;
150		goto retry;
151	}
152	Dprint((statp->options & RES_DEBUG) ||
153	       ((statp->pfcode & RES_PRF_REPLY) &&
154		(statp->pfcode & RES_PRF_HEAD1)),
155	       (stdout, ";; got answer:\n"));
156
157	DprintQ((statp->options & RES_DEBUG) ||
158		(statp->pfcode & RES_PRF_REPLY),
159		(stdout, "%s", ""),
160		answer, (anslen > len) ? len : anslen);
161
162	Dprint(statp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n"));
163
164	free (nstatp);
165	free (newmsg);
166	dst_free_key(dstkey);
167	return (len);
168}
169
170/*! \file */
171