Merge from vendor branch OPENSSL:
[dragonfly.git] / contrib / bind-9.3 / lib / lwres / lwres_gabn.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001  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 WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: lwres_gabn.c,v 1.27.12.3 2004/03/08 09:05:10 marka Exp $ */
19
20 #include <config.h>
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <lwres/lwbuffer.h>
27 #include <lwres/lwpacket.h>
28 #include <lwres/lwres.h>
29 #include <lwres/result.h>
30
31 #include "context_p.h"
32 #include "assert_p.h"
33
34 lwres_result_t
35 lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req,
36                          lwres_lwpacket_t *pkt, lwres_buffer_t *b)
37 {
38         unsigned char *buf;
39         size_t buflen;
40         int ret;
41         size_t payload_length;
42         lwres_uint16_t datalen;
43
44         REQUIRE(ctx != NULL);
45         REQUIRE(req != NULL);
46         REQUIRE(req->name != NULL);
47         REQUIRE(pkt != NULL);
48         REQUIRE(b != NULL);
49
50         datalen = strlen(req->name);
51
52         payload_length = 4 + 4 + 2 + req->namelen + 1;
53
54         buflen = LWRES_LWPACKET_LENGTH + payload_length;
55         buf = CTXMALLOC(buflen);
56         if (buf == NULL)
57                 return (LWRES_R_NOMEMORY);
58
59         lwres_buffer_init(b, buf, buflen);
60
61         pkt->length = buflen;
62         pkt->version = LWRES_LWPACKETVERSION_0;
63         pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
64         pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
65         pkt->result = 0;
66         pkt->authtype = 0;
67         pkt->authlength = 0;
68
69         ret = lwres_lwpacket_renderheader(b, pkt);
70         if (ret != LWRES_R_SUCCESS) {
71                 lwres_buffer_invalidate(b);
72                 CTXFREE(buf, buflen);
73                 return (ret);
74         }
75
76         INSIST(SPACE_OK(b, payload_length));
77
78         /*
79          * Flags.
80          */
81         lwres_buffer_putuint32(b, req->flags);
82
83         /*
84          * Address types we'll accept.
85          */
86         lwres_buffer_putuint32(b, req->addrtypes);
87
88         /*
89          * Put the length and the data.  We know this will fit because we
90          * just checked for it.
91          */
92         lwres_buffer_putuint16(b, datalen);
93         lwres_buffer_putmem(b, (unsigned char *)req->name, datalen);
94         lwres_buffer_putuint8(b, 0); /* trailing NUL */
95
96         INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
97
98         return (LWRES_R_SUCCESS);
99 }
100
101 lwres_result_t
102 lwres_gabnresponse_render(lwres_context_t *ctx, lwres_gabnresponse_t *req,
103                           lwres_lwpacket_t *pkt, lwres_buffer_t *b)
104 {
105         unsigned char *buf;
106         size_t buflen;
107         int ret;
108         size_t payload_length;
109         lwres_uint16_t datalen;
110         lwres_addr_t *addr;
111         int x;
112
113         REQUIRE(ctx != NULL);
114         REQUIRE(req != NULL);
115         REQUIRE(pkt != NULL);
116         REQUIRE(b != NULL);
117
118         /* naliases, naddrs */
119         payload_length = 4 + 2 + 2;
120         /* real name encoding */
121         payload_length += 2 + req->realnamelen + 1;
122         /* each alias */
123         for (x = 0; x < req->naliases; x++)
124                 payload_length += 2 + req->aliaslen[x] + 1;
125         /* each address */
126         x = 0;
127         addr = LWRES_LIST_HEAD(req->addrs);
128         while (addr != NULL) {
129                 payload_length += 4 + 2;
130                 payload_length += addr->length;
131                 addr = LWRES_LIST_NEXT(addr, link);
132                 x++;
133         }
134         INSIST(x == req->naddrs);
135
136         buflen = LWRES_LWPACKET_LENGTH + payload_length;
137         buf = CTXMALLOC(buflen);
138         if (buf == NULL)
139                 return (LWRES_R_NOMEMORY);
140         lwres_buffer_init(b, buf, buflen);
141
142         pkt->length = buflen;
143         pkt->version = LWRES_LWPACKETVERSION_0;
144         pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
145         pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
146         pkt->authtype = 0;
147         pkt->authlength = 0;
148
149         ret = lwres_lwpacket_renderheader(b, pkt);
150         if (ret != LWRES_R_SUCCESS) {
151                 lwres_buffer_invalidate(b);
152                 CTXFREE(buf, buflen);
153                 return (ret);
154         }
155
156         /*
157          * Check space needed here.
158          */
159         INSIST(SPACE_OK(b, payload_length));
160
161         /* Flags. */
162         lwres_buffer_putuint32(b, req->flags);
163
164         /* encode naliases and naddrs */
165         lwres_buffer_putuint16(b, req->naliases);
166         lwres_buffer_putuint16(b, req->naddrs);
167
168         /* encode the real name */
169         datalen = req->realnamelen;
170         lwres_buffer_putuint16(b, datalen);
171         lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
172         lwres_buffer_putuint8(b, 0);
173
174         /* encode the aliases */
175         for (x = 0; x < req->naliases; x++) {
176                 datalen = req->aliaslen[x];
177                 lwres_buffer_putuint16(b, datalen);
178                 lwres_buffer_putmem(b, (unsigned char *)req->aliases[x],
179                                     datalen);
180                 lwres_buffer_putuint8(b, 0);
181         }
182
183         /* encode the addresses */
184         addr = LWRES_LIST_HEAD(req->addrs);
185         while (addr != NULL) {
186                 lwres_buffer_putuint32(b, addr->family);
187                 lwres_buffer_putuint16(b, addr->length);
188                 lwres_buffer_putmem(b, addr->address, addr->length);
189                 addr = LWRES_LIST_NEXT(addr, link);
190         }
191
192         INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
193         INSIST(LWRES_BUFFER_USEDCOUNT(b) == pkt->length);
194
195         return (LWRES_R_SUCCESS);
196 }
197
198 lwres_result_t
199 lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
200                         lwres_lwpacket_t *pkt, lwres_gabnrequest_t **structp)
201 {
202         int ret;
203         char *name;
204         lwres_gabnrequest_t *gabn;
205         lwres_uint32_t addrtypes;
206         lwres_uint32_t flags;
207         lwres_uint16_t namelen;
208
209         REQUIRE(ctx != NULL);
210         REQUIRE(pkt != NULL);
211         REQUIRE(b != NULL);
212         REQUIRE(structp != NULL && *structp == NULL);
213
214         if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
215                 return (LWRES_R_FAILURE);
216
217         if (!SPACE_REMAINING(b, 4 + 4))
218                 return (LWRES_R_UNEXPECTEDEND);
219
220         flags = lwres_buffer_getuint32(b);
221         addrtypes = lwres_buffer_getuint32(b);
222
223         /*
224          * Pull off the name itself
225          */
226         ret = lwres_string_parse(b, &name, &namelen);
227         if (ret != LWRES_R_SUCCESS)
228                 return (ret);
229
230         if (LWRES_BUFFER_REMAINING(b) != 0)
231                 return (LWRES_R_TRAILINGDATA);
232
233         gabn = CTXMALLOC(sizeof(lwres_gabnrequest_t));
234         if (gabn == NULL)
235                 return (LWRES_R_NOMEMORY);
236
237         gabn->flags = flags;
238         gabn->addrtypes = addrtypes;
239         gabn->name = name;
240         gabn->namelen = namelen;
241
242         *structp = gabn;
243         return (LWRES_R_SUCCESS);
244 }
245
246 lwres_result_t
247 lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
248                         lwres_lwpacket_t *pkt, lwres_gabnresponse_t **structp)
249 {
250         lwres_result_t ret;
251         unsigned int x;
252         lwres_uint32_t flags;
253         lwres_uint16_t naliases;
254         lwres_uint16_t naddrs;
255         lwres_gabnresponse_t *gabn;
256         lwres_addrlist_t addrlist;
257         lwres_addr_t *addr;
258
259         REQUIRE(ctx != NULL);
260         REQUIRE(pkt != NULL);
261         REQUIRE(b != NULL);
262         REQUIRE(structp != NULL && *structp == NULL);
263
264         gabn = NULL;
265
266         if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
267                 return (LWRES_R_FAILURE);
268
269         /*
270          * Pull off the name itself
271          */
272         if (!SPACE_REMAINING(b, 4 + 2 + 2))
273                 return (LWRES_R_UNEXPECTEDEND);
274         flags = lwres_buffer_getuint32(b);
275         naliases = lwres_buffer_getuint16(b);
276         naddrs = lwres_buffer_getuint16(b);
277
278         gabn = CTXMALLOC(sizeof(lwres_gabnresponse_t));
279         if (gabn == NULL)
280                 return (LWRES_R_NOMEMORY);
281         gabn->aliases = NULL;
282         gabn->aliaslen = NULL;
283         LWRES_LIST_INIT(gabn->addrs);
284         gabn->base = NULL;
285
286         gabn->flags = flags;
287         gabn->naliases = naliases;
288         gabn->naddrs = naddrs;
289
290         LWRES_LIST_INIT(addrlist);
291
292         if (naliases > 0) {
293                 gabn->aliases = CTXMALLOC(sizeof(char *) * naliases);
294                 if (gabn->aliases == NULL) {
295                         ret = LWRES_R_NOMEMORY;
296                         goto out;
297                 }
298
299                 gabn->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases);
300                 if (gabn->aliaslen == NULL) {
301                         ret = LWRES_R_NOMEMORY;
302                         goto out;
303                 }
304         }
305
306         for (x = 0; x < naddrs; x++) {
307                 addr = CTXMALLOC(sizeof(lwres_addr_t));
308                 if (addr == NULL) {
309                         ret = LWRES_R_NOMEMORY;
310                         goto out;
311                 }
312                 LWRES_LINK_INIT(addr, link);
313                 LWRES_LIST_APPEND(addrlist, addr, link);
314         }
315
316         /*
317          * Now, pull off the real name.
318          */
319         ret = lwres_string_parse(b, &gabn->realname, &gabn->realnamelen);
320         if (ret != LWRES_R_SUCCESS)
321                 goto out;
322
323         /*
324          * Parse off the aliases.
325          */
326         for (x = 0; x < gabn->naliases; x++) {
327                 ret = lwres_string_parse(b, &gabn->aliases[x],
328                                          &gabn->aliaslen[x]);
329                 if (ret != LWRES_R_SUCCESS)
330                         goto out;
331         }
332
333         /*
334          * Pull off the addresses.  We already strung the linked list
335          * up above.
336          */
337         addr = LWRES_LIST_HEAD(addrlist);
338         for (x = 0; x < gabn->naddrs; x++) {
339                 INSIST(addr != NULL);
340                 ret = lwres_addr_parse(b, addr);
341                 if (ret != LWRES_R_SUCCESS)
342                         goto out;
343                 addr = LWRES_LIST_NEXT(addr, link);
344         }
345
346         if (LWRES_BUFFER_REMAINING(b) != 0) {
347                 ret = LWRES_R_TRAILINGDATA;
348                 goto out;
349         }
350
351         gabn->addrs = addrlist;
352
353         *structp = gabn;
354         return (LWRES_R_SUCCESS);
355
356  out:
357         if (gabn != NULL) {
358                 if (gabn->aliases != NULL)
359                         CTXFREE(gabn->aliases, sizeof(char *) * naliases);
360                 if (gabn->aliaslen != NULL)
361                         CTXFREE(gabn->aliaslen,
362                                 sizeof(lwres_uint16_t) * naliases);
363                 addr = LWRES_LIST_HEAD(addrlist);
364                 while (addr != NULL) {
365                         LWRES_LIST_UNLINK(addrlist, addr, link);
366                         CTXFREE(addr, sizeof(lwres_addr_t));
367                         addr = LWRES_LIST_HEAD(addrlist);
368                 }
369                 CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
370         }
371
372         return (ret);
373 }
374
375 void
376 lwres_gabnrequest_free(lwres_context_t *ctx, lwres_gabnrequest_t **structp)
377 {
378         lwres_gabnrequest_t *gabn;
379
380         REQUIRE(ctx != NULL);
381         REQUIRE(structp != NULL && *structp != NULL);
382
383         gabn = *structp;
384         *structp = NULL;
385
386         CTXFREE(gabn, sizeof(lwres_gabnrequest_t));
387 }
388
389 void
390 lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp)
391 {
392         lwres_gabnresponse_t *gabn;
393         lwres_addr_t *addr;
394
395         REQUIRE(ctx != NULL);
396         REQUIRE(structp != NULL && *structp != NULL);
397
398         gabn = *structp;
399         *structp = NULL;
400
401         if (gabn->naliases > 0) {
402                 CTXFREE(gabn->aliases, sizeof(char *) * gabn->naliases);
403                 CTXFREE(gabn->aliaslen,
404                         sizeof(lwres_uint16_t) * gabn->naliases);
405         }
406         addr = LWRES_LIST_HEAD(gabn->addrs);
407         while (addr != NULL) {
408                 LWRES_LIST_UNLINK(gabn->addrs, addr, link);
409                 CTXFREE(addr, sizeof(lwres_addr_t));
410                 addr = LWRES_LIST_HEAD(gabn->addrs);
411         }
412         if (gabn->base != NULL)
413                 CTXFREE(gabn->base, gabn->baselen);
414         CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
415 }