Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / isc-dhcp / minires / res_sendsigned.c
1 #include <sys/types.h>
2 #include <sys/param.h>
3
4 #include <netinet/in.h>
5 #include <arpa/inet.h>
6 #include <sys/socket.h>
7
8 #include <errno.h>
9 #include <netdb.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14
15 #include "minires/minires.h"
16 #include "arpa/nameser.h"
17
18 #include <isc-dhcp/dst.h>
19
20 /* res_nsendsigned */
21 isc_result_t
22 res_nsendsigned(res_state statp,
23                 double *msg, unsigned msglen, ns_tsig_key *key,
24                 double *answer, unsigned anslen, unsigned *anssize)
25 {
26         res_state nstatp;
27         DST_KEY *dstkey;
28         int usingTCP = 0;
29         double *newmsg;
30         unsigned newmsglen;
31         unsigned bufsize, siglen;
32         u_char sig[64];
33         HEADER *hp;
34         time_t tsig_time;
35         unsigned ret;
36         isc_result_t rcode;
37
38         dst_init();
39
40         nstatp = (res_state) malloc(sizeof(*statp));
41         if (nstatp == NULL)
42                 return ISC_R_NOMEMORY;
43         memcpy(nstatp, statp, sizeof(*statp));
44
45         bufsize = msglen + 1024;
46         newmsg = (double *) malloc(bufsize);
47         if (newmsg == NULL)
48                 return ISC_R_NOMEMORY;
49         memcpy(newmsg, msg, msglen);
50         newmsglen = msglen;
51
52         if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1)
53                 dstkey = NULL;
54         else
55                 dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
56                                            NS_KEY_TYPE_AUTH_ONLY,
57                                            NS_KEY_PROT_ANY,
58                                            key->data, key->len);
59         if (dstkey == NULL) {
60                 free(nstatp);
61                 free(newmsg);
62                 return ISC_R_BADKEY;
63         }
64
65         nstatp->nscount = 1;
66         siglen = sizeof(sig);
67         rcode = ns_sign((u_char *)newmsg, &newmsglen, bufsize,
68                         NOERROR, dstkey, NULL, 0,
69                         sig, &siglen, 0);
70         if (rcode != ISC_R_SUCCESS) {
71                 free (nstatp);
72                 free (newmsg);
73                 return rcode;
74         }
75
76         if (newmsglen > PACKETSZ || (nstatp->options & RES_IGNTC))
77                 usingTCP = 1;
78         if (usingTCP == 0)
79                 nstatp->options |= RES_IGNTC;
80         else
81                 nstatp->options |= RES_USEVC;
82
83 retry:
84
85         rcode = res_nsend(nstatp, newmsg, newmsglen, answer, anslen, &ret);
86         if (rcode != ISC_R_SUCCESS) {
87                 free (nstatp);
88                 free (newmsg);
89                 return rcode;
90         }
91
92         anslen = ret;
93         rcode = ns_verify((u_char *)answer, &anslen, dstkey, sig, siglen,
94                           NULL, NULL, &tsig_time,
95                           (nstatp->options & RES_KEEPTSIG) ? 1 : 0);
96         if (rcode != ISC_R_SUCCESS) {
97                 Dprint(nstatp->pfcode & RES_PRF_REPLY,
98                        (stdout, ";; TSIG invalid (%s)\n", p_rcode(ret)));
99                 free (nstatp);
100                 free (newmsg);
101                 return rcode;
102         }
103         Dprint(nstatp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n"));
104
105         hp = (HEADER *) answer;
106         if (hp->tc && usingTCP == 0) {
107                 nstatp->options &= ~RES_IGNTC;
108                 usingTCP = 1;
109                 goto retry;
110         }
111
112         free (nstatp);
113         free (newmsg);
114         *anssize = anslen;
115         return ISC_R_SUCCESS;
116 }