xref: /illumos-gate/usr/src/lib/libresolv2/common/resolv/res_sendsigned.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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 */
28 int
29 res_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 
103 retry:
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