Merge from vendor branch FILE:
[dragonfly.git] / contrib / dhcp-3.0 / minires / res_sendsigned.c
1 /*
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (c) 1995-2003 by Internet Software Consortium
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  *   Internet Systems Consortium, Inc.
18  *   950 Charter Street
19  *   Redwood City, CA 94063
20  *   <info@isc.org>
21  *   http://www.isc.org/
22  */
23
24 #include <sys/types.h>
25 #include <sys/param.h>
26
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <sys/socket.h>
30
31 #include <errno.h>
32 #include <netdb.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #include "minires/minires.h"
39 #include "arpa/nameser.h"
40
41 #include <isc-dhcp/dst.h>
42
43 /* res_nsendsigned */
44 isc_result_t
45 res_nsendsigned(res_state statp,
46                 double *msg, unsigned msglen, ns_tsig_key *key,
47                 double *answer, unsigned anslen, unsigned *anssize)
48 {
49         res_state nstatp;
50         DST_KEY *dstkey;
51         int usingTCP = 0;
52         double *newmsg;
53         unsigned newmsglen;
54         unsigned bufsize, siglen;
55         u_char sig[64];
56         HEADER *hp;
57         time_t tsig_time;
58         unsigned ret;
59         isc_result_t rcode;
60
61         dst_init();
62
63         nstatp = (res_state) malloc(sizeof(*statp));
64         if (nstatp == NULL)
65                 return ISC_R_NOMEMORY;
66         memcpy(nstatp, statp, sizeof(*statp));
67
68         bufsize = msglen + 1024;
69         newmsg = (double *) malloc(bufsize);
70         if (newmsg == NULL)
71                 return ISC_R_NOMEMORY;
72         memcpy(newmsg, msg, msglen);
73         newmsglen = msglen;
74
75         if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1)
76                 dstkey = NULL;
77         else
78                 dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
79                                            NS_KEY_TYPE_AUTH_ONLY,
80                                            NS_KEY_PROT_ANY,
81                                            key->data, key->len);
82         if (dstkey == NULL) {
83                 free(nstatp);
84                 free(newmsg);
85                 return ISC_R_BADKEY;
86         }
87
88         nstatp->nscount = 1;
89         siglen = sizeof(sig);
90         rcode = ns_sign((u_char *)newmsg, &newmsglen, bufsize,
91                         NOERROR, dstkey, NULL, 0,
92                         sig, &siglen, 0);
93         if (rcode != ISC_R_SUCCESS) {
94                 free (nstatp);
95                 free (newmsg);
96                 return rcode;
97         }
98
99         if (newmsglen > PACKETSZ || (nstatp->options & RES_IGNTC))
100                 usingTCP = 1;
101         if (usingTCP == 0)
102                 nstatp->options |= RES_IGNTC;
103         else
104                 nstatp->options |= RES_USEVC;
105
106 retry:
107
108         rcode = res_nsend(nstatp, newmsg, newmsglen, answer, anslen, &ret);
109         if (rcode != ISC_R_SUCCESS) {
110                 free (nstatp);
111                 free (newmsg);
112                 return rcode;
113         }
114
115         anslen = ret;
116         rcode = ns_verify((u_char *)answer, &anslen, dstkey, sig, siglen,
117                           NULL, NULL, &tsig_time,
118                           (nstatp->options & RES_KEEPTSIG) ? 1 : 0);
119         if (rcode != ISC_R_SUCCESS) {
120                 Dprint(nstatp->pfcode & RES_PRF_REPLY,
121                        (stdout, ";; TSIG invalid (%s)\n", p_rcode(ret)));
122                 free (nstatp);
123                 free (newmsg);
124                 return rcode;
125         }
126         Dprint(nstatp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n"));
127
128         hp = (HEADER *) answer;
129         if (hp->tc && usingTCP == 0) {
130                 nstatp->options &= ~RES_IGNTC;
131                 usingTCP = 1;
132                 goto retry;
133         }
134
135         free (nstatp);
136         free (newmsg);
137         *anssize = anslen;
138         return ISC_R_SUCCESS;
139 }