Merge from vendor branch GCC:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / bind / resolv / res_sendsigned.c
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                 errno = ENOMEM;
56                 return (-1);
57         }
58         memcpy(newmsg, msg, msglen);
59         newmsglen = msglen;
60
61         if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1)
62                 dstkey = NULL;
63         else
64                 dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
65                                            NS_KEY_TYPE_AUTH_ONLY,
66                                            NS_KEY_PROT_ANY,
67                                            key->data, key->len);
68         if (dstkey == NULL) {
69                 errno = EINVAL;
70                 free(nstatp);
71                 free(newmsg);
72                 return (-1);
73         }
74
75         nstatp->nscount = 1;
76         siglen = sizeof(sig);
77         ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0,
78                       sig, &siglen, 0);
79         if (ret < 0) {
80                 free (nstatp);
81                 free (newmsg);
82                 dst_free_key(dstkey);
83                 if (ret == NS_TSIG_ERROR_NO_SPACE)
84                         errno  = EMSGSIZE;
85                 else if (ret == -1)
86                         errno  = EINVAL;
87                 return (ret);
88         }
89
90         if (newmsglen > PACKETSZ || nstatp->options & RES_USEVC)
91                 usingTCP = 1;
92         if (usingTCP == 0)
93                 nstatp->options |= RES_IGNTC;
94         else
95                 nstatp->options |= RES_USEVC;
96         /*
97          * Stop res_send printing the answer.
98          */
99         nstatp->options &= ~RES_DEBUG;
100         nstatp->pfcode &= ~RES_PRF_REPLY;
101
102 retry:
103
104         len = res_nsend(nstatp, newmsg, newmsglen, answer, anslen);
105         if (ret < 0) {
106                 free (nstatp);
107                 free (newmsg);
108                 dst_free_key(dstkey);
109                 return (ret);
110         }
111
112         ret = ns_verify(answer, &len, dstkey, sig, siglen,
113                         NULL, NULL, &tsig_time, nstatp->options & RES_KEEPTSIG);
114         if (ret != 0) {
115                 Dprint((statp->options & RES_DEBUG) ||
116                        ((statp->pfcode & RES_PRF_REPLY) &&
117                         (statp->pfcode & RES_PRF_HEAD1)),
118                        (stdout, ";; got answer:\n"));
119
120                 DprintQ((statp->options & RES_DEBUG) ||
121                         (statp->pfcode & RES_PRF_REPLY),
122                         (stdout, "%s", ""),
123                         answer, (anslen > len) ? len : anslen);
124
125                 Dprint(statp->pfcode & RES_PRF_REPLY,
126                        (stdout, ";; TSIG invalid (%s)\n", p_rcode(ret)));
127                 free (nstatp);
128                 free (newmsg);
129                 dst_free_key(dstkey);
130                 if (ret == -1)
131                         errno = EINVAL;
132                 else
133                         errno = ENOTTY;
134                 return (-1);
135         }
136
137         hp = (HEADER *) answer;
138         if (hp->tc && !usingTCP && (statp->options & RES_IGNTC) == 0U) {
139                 nstatp->options &= ~RES_IGNTC;
140                 usingTCP = 1;
141                 goto retry;
142         }
143         Dprint((statp->options & RES_DEBUG) ||
144                ((statp->pfcode & RES_PRF_REPLY) &&
145                 (statp->pfcode & RES_PRF_HEAD1)),
146                (stdout, ";; got answer:\n"));
147
148         DprintQ((statp->options & RES_DEBUG) ||
149                 (statp->pfcode & RES_PRF_REPLY),
150                 (stdout, "%s", ""),
151                 answer, (anslen > len) ? len : anslen);
152
153         Dprint(statp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n"));
154
155         free (nstatp);
156         free (newmsg);
157         dst_free_key(dstkey);
158         return (len);
159 }