Merge branch 'vendor/OPENSSH'
[dragonfly.git] / contrib / bind / lib / lwres / getrrset.c
1 /*
2  * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or 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: getrrset.c,v 1.18 2007/06/19 23:47:22 tbox Exp $ */
19
20 /*! \file */
21
22 /**
23  * DESCRIPTION
24  * 
25  *    lwres_getrrsetbyname() gets a set of resource records associated with
26  *    a hostname, class, and type. hostname is a pointer a to
27  *    null-terminated string. The flags field is currently unused and must
28  *    be zero.
29  * 
30  *    After a successful call to lwres_getrrsetbyname(), *res is a pointer
31  *    to an #rrsetinfo structure, containing a list of one or more #rdatainfo
32  *    structures containing resource records and potentially another list of
33  *    rdatainfo structures containing SIG resource records associated with
34  *    those records. The members #rri_rdclass and #rri_rdtype are copied from
35  *    the parameters. #rri_ttl and #rri_name are properties of the obtained
36  *    rrset. The resource records contained in #rri_rdatas and #rri_sigs are
37  *    in uncompressed DNS wire format. Properties of the rdataset are
38  *    represented in the #rri_flags bitfield. If the #RRSET_VALIDATED bit is
39  *    set, the data has been DNSSEC validated and the signatures verified.
40  * 
41  *    All of the information returned by lwres_getrrsetbyname() is
42  *    dynamically allocated: the rrsetinfo and rdatainfo structures, and the
43  *    canonical host name strings pointed to by the rrsetinfostructure.
44  *    Memory allocated for the dynamically allocated structures created by a
45  *    successful call to lwres_getrrsetbyname() is released by
46  *    lwres_freerrset(). rrset is a pointer to a struct rrset created by a
47  *    call to lwres_getrrsetbyname().
48  * 
49  *    The following structures are used:
50  * 
51  * \code
52  * struct  rdatainfo {
53  *         unsigned int            rdi_length;     // length of data
54  *         unsigned char           *rdi_data;      // record data
55  * };
56  * 
57  * struct  rrsetinfo {
58  *         unsigned int            rri_flags;      // RRSET_VALIDATED...
59  *         unsigned int            rri_rdclass;    // class number
60  *         unsigned int            rri_rdtype;     // RR type number
61  *         unsigned int            rri_ttl;        // time to live
62  *         unsigned int            rri_nrdatas;    // size of rdatas array
63  *         unsigned int            rri_nsigs;      // size of sigs array
64  *         char                    *rri_name;      // canonical name
65  *         struct rdatainfo        *rri_rdatas;    // individual records
66  *         struct rdatainfo        *rri_sigs;      // individual signatures
67  * };
68  * \endcode
69  * 
70  * \section getrrset_return Return Values
71  * 
72  *    lwres_getrrsetbyname() returns zero on success, and one of the
73  *    following error codes if an error occurred:
74  * 
75  * \li   #ERRSET_NONAME: the name does not exist
76  * 
77  * \li   #ERRSET_NODATA:
78  *           the name exists, but does not have data of the desired type
79  * 
80  * \li   #ERRSET_NOMEMORY:
81  *           memory could not be allocated
82  * 
83  * \li   #ERRSET_INVAL:
84  *           a parameter is invalid
85  * 
86  * \li   #ERRSET_FAIL:
87  *           other failure
88  */
89
90 #include <config.h>
91
92 #include <string.h>
93 #include <errno.h>
94 #include <stdlib.h>
95
96 #include <lwres/lwres.h>
97 #include <lwres/net.h>
98 #include <lwres/netdb.h>        /* XXX #include <netdb.h> */
99
100 #include "assert_p.h"
101
102 /*!
103  * Structure to map results
104  */
105 static unsigned int
106 lwresult_to_result(lwres_result_t lwresult) {
107         switch (lwresult) {
108         case LWRES_R_SUCCESS:   return (ERRSET_SUCCESS);
109         case LWRES_R_NOMEMORY:  return (ERRSET_NOMEMORY);
110         case LWRES_R_NOTFOUND:  return (ERRSET_NONAME);
111         case LWRES_R_TYPENOTFOUND: return (ERRSET_NODATA);
112         default:                return (ERRSET_FAIL);
113         }
114 }
115
116 /*@{*/
117 /*!
118  * malloc / calloc functions that guarantee to only
119  * return NULL if there is an error, like they used
120  * to before the ANSI C committee broke them.
121  */
122
123 static void *
124 sane_malloc(size_t size) {
125         if (size == 0U)
126                 size = 1;
127         return (malloc(size));
128 }
129
130 static void *
131 sane_calloc(size_t number, size_t size) {
132         size_t len = number * size;
133         void *mem  = sane_malloc(len);
134         if (mem != NULL)
135                 memset(mem, 0, len);
136         return (mem);
137 }
138 /*@}*/
139
140 /*% Returns a set of resource records associated with a hostname, class, and type. hostname is a pointer a to null-terminated string. */
141 int
142 lwres_getrrsetbyname(const char *hostname, unsigned int rdclass,
143                      unsigned int rdtype, unsigned int flags,
144                      struct rrsetinfo **res)
145 {
146         lwres_context_t *lwrctx = NULL;
147         lwres_result_t lwresult;
148         lwres_grbnresponse_t *response = NULL;
149         struct rrsetinfo *rrset = NULL;
150         unsigned int i;
151         unsigned int lwflags;
152         unsigned int result;
153
154         if (rdclass > 0xffff || rdtype > 0xffff) {
155                 result = ERRSET_INVAL;
156                 goto fail;
157         }
158
159         /*
160          * Don't allow queries of class or type ANY
161          */
162         if (rdclass == 0xff || rdtype == 0xff) {
163                 result = ERRSET_INVAL;
164                 goto fail;
165         }
166
167         lwresult = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
168         if (lwresult != LWRES_R_SUCCESS) {
169                 result = lwresult_to_result(lwresult);
170                 goto fail;
171         }
172         (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
173
174         /*
175          * If any input flags were defined, lwflags would be set here
176          * based on them
177          */
178         UNUSED(flags);
179         lwflags = 0;
180
181         lwresult = lwres_getrdatabyname(lwrctx, hostname,
182                                         (lwres_uint16_t)rdclass, 
183                                         (lwres_uint16_t)rdtype,
184                                         lwflags, &response);
185         if (lwresult != LWRES_R_SUCCESS) {
186                 result = lwresult_to_result(lwresult);
187                 goto fail;
188         }
189
190         rrset = sane_malloc(sizeof(struct rrsetinfo));
191         if (rrset == NULL) {
192                 result = ERRSET_NOMEMORY;
193                 goto fail;
194         }
195         rrset->rri_name = NULL;
196         rrset->rri_rdclass = response->rdclass;
197         rrset->rri_rdtype = response->rdtype;
198         rrset->rri_ttl = response->ttl;
199         rrset->rri_flags = 0;
200         rrset->rri_nrdatas = 0;
201         rrset->rri_rdatas = NULL;
202         rrset->rri_nsigs = 0;
203         rrset->rri_sigs = NULL;
204
205         rrset->rri_name = sane_malloc(response->realnamelen + 1);
206         if (rrset->rri_name == NULL) {
207                 result = ERRSET_NOMEMORY;
208                 goto fail;
209         }
210         strncpy(rrset->rri_name, response->realname, response->realnamelen);
211         rrset->rri_name[response->realnamelen] = 0;
212
213         if ((response->flags & LWRDATA_VALIDATED) != 0)
214                 rrset->rri_flags |= RRSET_VALIDATED;
215
216         rrset->rri_nrdatas = response->nrdatas;
217         rrset->rri_rdatas = sane_calloc(rrset->rri_nrdatas,
218                                    sizeof(struct rdatainfo));
219         if (rrset->rri_rdatas == NULL) {
220                 result = ERRSET_NOMEMORY;
221                 goto fail;
222         }
223         for (i = 0; i < rrset->rri_nrdatas; i++) {
224                 rrset->rri_rdatas[i].rdi_length = response->rdatalen[i];
225                 rrset->rri_rdatas[i].rdi_data =
226                                 sane_malloc(rrset->rri_rdatas[i].rdi_length);
227                 if (rrset->rri_rdatas[i].rdi_data == NULL) {
228                         result = ERRSET_NOMEMORY;
229                         goto fail;
230                 }
231                 memcpy(rrset->rri_rdatas[i].rdi_data, response->rdatas[i],
232                        rrset->rri_rdatas[i].rdi_length);
233         }
234         rrset->rri_nsigs = response->nsigs;
235         rrset->rri_sigs = sane_calloc(rrset->rri_nsigs,
236                                       sizeof(struct rdatainfo));
237         if (rrset->rri_sigs == NULL) {
238                 result = ERRSET_NOMEMORY;
239                 goto fail;
240         }
241         for (i = 0; i < rrset->rri_nsigs; i++) {
242                 rrset->rri_sigs[i].rdi_length = response->siglen[i];
243                 rrset->rri_sigs[i].rdi_data =
244                                 sane_malloc(rrset->rri_sigs[i].rdi_length);
245                 if (rrset->rri_sigs[i].rdi_data == NULL) {
246                         result = ERRSET_NOMEMORY;
247                         goto fail;
248                 }
249                 memcpy(rrset->rri_sigs[i].rdi_data, response->sigs[i],
250                        rrset->rri_sigs[i].rdi_length);
251         }
252
253         lwres_grbnresponse_free(lwrctx, &response);
254         lwres_conf_clear(lwrctx);
255         lwres_context_destroy(&lwrctx);
256         *res = rrset;
257         return (ERRSET_SUCCESS);
258  fail:
259         if (rrset != NULL)
260                 lwres_freerrset(rrset);
261         if (response != NULL)
262                 lwres_grbnresponse_free(lwrctx, &response);
263         if (lwrctx != NULL) {
264                 lwres_conf_clear(lwrctx);
265                 lwres_context_destroy(&lwrctx);
266         }
267         return (result);
268 }
269
270 /*% Releases memory allocated for the dynamically allocated structures created by a successful call to lwres_getrrsetbyname(). */
271 void
272 lwres_freerrset(struct rrsetinfo *rrset) {
273         unsigned int i;
274         for (i = 0; i < rrset->rri_nrdatas; i++) {
275                 if (rrset->rri_rdatas[i].rdi_data == NULL)
276                         break;
277                 free(rrset->rri_rdatas[i].rdi_data);
278         }
279         free(rrset->rri_rdatas);
280         for (i = 0; i < rrset->rri_nsigs; i++) {
281                 if (rrset->rri_sigs[i].rdi_data == NULL)
282                         break;
283                 free(rrset->rri_sigs[i].rdi_data);
284         }
285         free(rrset->rri_sigs);
286         free(rrset->rri_name);
287         free(rrset);
288 }