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