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