]> andersk Git - gssapi-openssh.git/blob - openssh/openbsd-compat/getrrsetbyname.c
merged OpenSSH 3.8.1p1 to trunk
[gssapi-openssh.git] / openssh / openbsd-compat / getrrsetbyname.c
1 /* OPENBSD ORIGINAL: lib/libc/net/getrrsetbyname.c */
2
3 /* $OpenBSD: getrrsetbyname.c,v 1.7 2003/03/07 07:34:14 itojun Exp $ */
4
5 /*
6  * Copyright (c) 2001 Jakob Schlyter. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /*
32  * Portions Copyright (c) 1999-2001 Internet Software Consortium.
33  *
34  * Permission to use, copy, modify, and distribute this software for any
35  * purpose with or without fee is hereby granted, provided that the above
36  * copyright notice and this permission notice appear in all copies.
37  *
38  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
39  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
41  * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
42  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
43  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
44  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
45  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46  */
47
48 #include "includes.h"
49
50 #ifndef HAVE_GETRRSETBYNAME
51
52 #include "getrrsetbyname.h"
53
54 #define ANSWER_BUFFER_SIZE 1024*64
55
56 struct dns_query {
57         char                    *name;
58         u_int16_t               type;
59         u_int16_t               class;
60         struct dns_query        *next;
61 };
62
63 struct dns_rr {
64         char                    *name;
65         u_int16_t               type;
66         u_int16_t               class;
67         u_int16_t               ttl;
68         u_int16_t               size;
69         void                    *rdata;
70         struct dns_rr           *next;
71 };
72
73 struct dns_response {
74         HEADER                  header;
75         struct dns_query        *query;
76         struct dns_rr           *answer;
77         struct dns_rr           *authority;
78         struct dns_rr           *additional;
79 };
80
81 static struct dns_response *parse_dns_response(const u_char *, int);
82 static struct dns_query *parse_dns_qsection(const u_char *, int,
83     const u_char **, int);
84 static struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **,
85     int);
86
87 static void free_dns_query(struct dns_query *);
88 static void free_dns_rr(struct dns_rr *);
89 static void free_dns_response(struct dns_response *);
90
91 static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t);
92
93 /*
94  * Inline versions of get/put short/long.  Pointer is advanced.
95  *
96  * These macros demonstrate the property of C whereby it can be
97  * portable or it can be elegant but rarely both.
98  */
99
100 #ifndef INT32SZ
101 # define INT32SZ        4
102 #endif
103 #ifndef INT16SZ
104 # define INT16SZ        2
105 #endif
106
107 #ifndef GETSHORT
108 #define GETSHORT(s, cp) { \
109         register u_char *t_cp = (u_char *)(cp); \
110         (s) = ((u_int16_t)t_cp[0] << 8) \
111             | ((u_int16_t)t_cp[1]) \
112             ; \
113         (cp) += INT16SZ; \
114 }
115 #endif
116
117 #ifndef GETLONG
118 #define GETLONG(l, cp) { \
119         register u_char *t_cp = (u_char *)(cp); \
120         (l) = ((u_int32_t)t_cp[0] << 24) \
121             | ((u_int32_t)t_cp[1] << 16) \
122             | ((u_int32_t)t_cp[2] << 8) \
123             | ((u_int32_t)t_cp[3]) \
124             ; \
125         (cp) += INT32SZ; \
126 }
127 #endif
128
129 /*
130  * Routines to insert/extract short/long's.
131  */
132
133 #ifndef HAVE__GETSHORT
134 static u_int16_t
135 _getshort(msgp)
136         register const u_char *msgp;
137 {
138         register u_int16_t u;
139
140         GETSHORT(u, msgp);
141         return (u);
142 }
143 #endif
144
145 #ifndef HAVE__GETLONG
146 static u_int32_t
147 _getlong(msgp)
148         register const u_char *msgp;
149 {
150         register u_int32_t u;
151
152         GETLONG(u, msgp);
153         return (u);
154 }
155 #endif
156
157 int
158 getrrsetbyname(const char *hostname, unsigned int rdclass,
159     unsigned int rdtype, unsigned int flags,
160     struct rrsetinfo **res)
161 {
162         int result;
163         struct rrsetinfo *rrset = NULL;
164         struct dns_response *response;
165         struct dns_rr *rr;
166         struct rdatainfo *rdata;
167         int length;
168         unsigned int index_ans, index_sig;
169         u_char answer[ANSWER_BUFFER_SIZE];
170
171         /* check for invalid class and type */
172         if (rdclass > 0xffff || rdtype > 0xffff) {
173                 result = ERRSET_INVAL;
174                 goto fail;
175         }
176
177         /* don't allow queries of class or type ANY */
178         if (rdclass == 0xff || rdtype == 0xff) {
179                 result = ERRSET_INVAL;
180                 goto fail;
181         }
182
183         /* don't allow flags yet, unimplemented */
184         if (flags) {
185                 result = ERRSET_INVAL;
186                 goto fail;
187         }
188
189         /* initialize resolver */
190         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
191                 result = ERRSET_FAIL;
192                 goto fail;
193         }
194
195 #ifdef DEBUG
196         _res.options |= RES_DEBUG;
197 #endif /* DEBUG */
198
199 #ifdef RES_USE_DNSSEC
200         /* turn on DNSSEC if EDNS0 is configured */
201         if (_res.options & RES_USE_EDNS0)
202                 _res.options |= RES_USE_DNSSEC;
203 #endif /* RES_USE_DNSEC */
204
205         /* make query */
206         length = res_query(hostname, (signed int) rdclass, (signed int) rdtype,
207             answer, sizeof(answer));
208         if (length < 0) {
209                 switch(h_errno) {
210                 case HOST_NOT_FOUND:
211                         result = ERRSET_NONAME;
212                         goto fail;
213                 case NO_DATA:
214                         result = ERRSET_NODATA;
215                         goto fail;
216                 default:
217                         result = ERRSET_FAIL;
218                         goto fail;
219                 }
220         }
221
222         /* parse result */
223         response = parse_dns_response(answer, length);
224         if (response == NULL) {
225                 result = ERRSET_FAIL;
226                 goto fail;
227         }
228
229         if (response->header.qdcount != 1) {
230                 result = ERRSET_FAIL;
231                 goto fail;
232         }
233
234         /* initialize rrset */
235         rrset = calloc(1, sizeof(struct rrsetinfo));
236         if (rrset == NULL) {
237                 result = ERRSET_NOMEMORY;
238                 goto fail;
239         }
240         rrset->rri_rdclass = response->query->class;
241         rrset->rri_rdtype = response->query->type;
242         rrset->rri_ttl = response->answer->ttl;
243         rrset->rri_nrdatas = response->header.ancount;
244
245 #ifdef HAVE_HEADER_AD
246         /* check for authenticated data */
247         if (response->header.ad == 1)
248                 rrset->rri_flags |= RRSET_VALIDATED;
249 #endif
250
251         /* copy name from answer section */
252         length = strlen(response->answer->name);
253         rrset->rri_name = malloc(length + 1);
254         if (rrset->rri_name == NULL) {
255                 result = ERRSET_NOMEMORY;
256                 goto fail;
257         }
258         strlcpy(rrset->rri_name, response->answer->name, length + 1);
259
260         /* count answers */
261         rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass,
262             rrset->rri_rdtype);
263         rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass,
264             T_SIG);
265
266         /* allocate memory for answers */
267         rrset->rri_rdatas = calloc(rrset->rri_nrdatas,
268             sizeof(struct rdatainfo));
269         if (rrset->rri_rdatas == NULL) {
270                 result = ERRSET_NOMEMORY;
271                 goto fail;
272         }
273
274         /* allocate memory for signatures */
275         rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo));
276         if (rrset->rri_sigs == NULL) {
277                 result = ERRSET_NOMEMORY;
278                 goto fail;
279         }
280
281         /* copy answers & signatures */
282         for (rr = response->answer, index_ans = 0, index_sig = 0;
283             rr; rr = rr->next) {
284
285                 rdata = NULL;
286
287                 if (rr->class == rrset->rri_rdclass &&
288                     rr->type  == rrset->rri_rdtype)
289                         rdata = &rrset->rri_rdatas[index_ans++];
290
291                 if (rr->class == rrset->rri_rdclass &&
292                     rr->type  == T_SIG)
293                         rdata = &rrset->rri_sigs[index_sig++];
294
295                 if (rdata) {
296                         rdata->rdi_length = rr->size;
297                         rdata->rdi_data   = malloc(rr->size);
298
299                         if (rdata->rdi_data == NULL) {
300                                 result = ERRSET_NOMEMORY;
301                                 goto fail;
302                         }
303                         memcpy(rdata->rdi_data, rr->rdata, rr->size);
304                 }
305         }
306
307         *res = rrset;
308         return (ERRSET_SUCCESS);
309
310 fail:
311         if (rrset != NULL)
312                 freerrset(rrset);
313         return (result);
314 }
315
316 void
317 freerrset(struct rrsetinfo *rrset)
318 {
319         u_int16_t i;
320
321         if (rrset == NULL)
322                 return;
323
324         if (rrset->rri_rdatas) {
325                 for (i = 0; i < rrset->rri_nrdatas; i++) {
326                         if (rrset->rri_rdatas[i].rdi_data == NULL)
327                                 break;
328                         free(rrset->rri_rdatas[i].rdi_data);
329                 }
330                 free(rrset->rri_rdatas);
331         }
332
333         if (rrset->rri_sigs) {
334                 for (i = 0; i < rrset->rri_nsigs; i++) {
335                         if (rrset->rri_sigs[i].rdi_data == NULL)
336                                 break;
337                         free(rrset->rri_sigs[i].rdi_data);
338                 }
339                 free(rrset->rri_sigs);
340         }
341
342         if (rrset->rri_name)
343                 free(rrset->rri_name);
344         free(rrset);
345 }
346
347 /*
348  * DNS response parsing routines
349  */
350 static struct dns_response *
351 parse_dns_response(const u_char *answer, int size)
352 {
353         struct dns_response *resp;
354         const u_char *cp;
355
356         /* allocate memory for the response */
357         resp = calloc(1, sizeof(*resp));
358         if (resp == NULL)
359                 return (NULL);
360
361         /* initialize current pointer */
362         cp = answer;
363
364         /* copy header */
365         memcpy(&resp->header, cp, HFIXEDSZ);
366         cp += HFIXEDSZ;
367
368         /* fix header byte order */
369         resp->header.qdcount = ntohs(resp->header.qdcount);
370         resp->header.ancount = ntohs(resp->header.ancount);
371         resp->header.nscount = ntohs(resp->header.nscount);
372         resp->header.arcount = ntohs(resp->header.arcount);
373
374         /* there must be at least one query */
375         if (resp->header.qdcount < 1) {
376                 free_dns_response(resp);
377                 return (NULL);
378         }
379
380         /* parse query section */
381         resp->query = parse_dns_qsection(answer, size, &cp,
382             resp->header.qdcount);
383         if (resp->header.qdcount && resp->query == NULL) {
384                 free_dns_response(resp);
385                 return (NULL);
386         }
387
388         /* parse answer section */
389         resp->answer = parse_dns_rrsection(answer, size, &cp,
390             resp->header.ancount);
391         if (resp->header.ancount && resp->answer == NULL) {
392                 free_dns_response(resp);
393                 return (NULL);
394         }
395
396         /* parse authority section */
397         resp->authority = parse_dns_rrsection(answer, size, &cp,
398             resp->header.nscount);
399         if (resp->header.nscount && resp->authority == NULL) {
400                 free_dns_response(resp);
401                 return (NULL);
402         }
403
404         /* parse additional section */
405         resp->additional = parse_dns_rrsection(answer, size, &cp,
406             resp->header.arcount);
407         if (resp->header.arcount && resp->additional == NULL) {
408                 free_dns_response(resp);
409                 return (NULL);
410         }
411
412         return (resp);
413 }
414
415 static struct dns_query *
416 parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count)
417 {
418         struct dns_query *head, *curr, *prev;
419         int i, length;
420         char name[MAXDNAME];
421
422         for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
423
424                 /* allocate and initialize struct */
425                 curr = calloc(1, sizeof(struct dns_query));
426                 if (curr == NULL) {
427                         free_dns_query(head);
428                         return (NULL);
429                 }
430                 if (head == NULL)
431                         head = curr;
432                 if (prev != NULL)
433                         prev->next = curr;
434
435                 /* name */
436                 length = dn_expand(answer, answer + size, *cp, name,
437                     sizeof(name));
438                 if (length < 0) {
439                         free_dns_query(head);
440                         return (NULL);
441                 }
442                 curr->name = strdup(name);
443                 if (curr->name == NULL) {
444                         free_dns_query(head);
445                         return (NULL);
446                 }
447                 *cp += length;
448
449                 /* type */
450                 curr->type = _getshort(*cp);
451                 *cp += INT16SZ;
452
453                 /* class */
454                 curr->class = _getshort(*cp);
455                 *cp += INT16SZ;
456         }
457
458         return (head);
459 }
460
461 static struct dns_rr *
462 parse_dns_rrsection(const u_char *answer, int size, const u_char **cp, int count)
463 {
464         struct dns_rr *head, *curr, *prev;
465         int i, length;
466         char name[MAXDNAME];
467
468         for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
469
470                 /* allocate and initialize struct */
471                 curr = calloc(1, sizeof(struct dns_rr));
472                 if (curr == NULL) {
473                         free_dns_rr(head);
474                         return (NULL);
475                 }
476                 if (head == NULL)
477                         head = curr;
478                 if (prev != NULL)
479                         prev->next = curr;
480
481                 /* name */
482                 length = dn_expand(answer, answer + size, *cp, name,
483                     sizeof(name));
484                 if (length < 0) {
485                         free_dns_rr(head);
486                         return (NULL);
487                 }
488                 curr->name = strdup(name);
489                 if (curr->name == NULL) {
490                         free_dns_rr(head);
491                         return (NULL);
492                 }
493                 *cp += length;
494
495                 /* type */
496                 curr->type = _getshort(*cp);
497                 *cp += INT16SZ;
498
499                 /* class */
500                 curr->class = _getshort(*cp);
501                 *cp += INT16SZ;
502
503                 /* ttl */
504                 curr->ttl = _getlong(*cp);
505                 *cp += INT32SZ;
506
507                 /* rdata size */
508                 curr->size = _getshort(*cp);
509                 *cp += INT16SZ;
510
511                 /* rdata itself */
512                 curr->rdata = malloc(curr->size);
513                 if (curr->rdata == NULL) {
514                         free_dns_rr(head);
515                         return (NULL);
516                 }
517                 memcpy(curr->rdata, *cp, curr->size);
518                 *cp += curr->size;
519         }
520
521         return (head);
522 }
523
524 static void
525 free_dns_query(struct dns_query *p)
526 {
527         if (p == NULL)
528                 return;
529
530         if (p->name)
531                 free(p->name);
532         free_dns_query(p->next);
533         free(p);
534 }
535
536 static void
537 free_dns_rr(struct dns_rr *p)
538 {
539         if (p == NULL)
540                 return;
541
542         if (p->name)
543                 free(p->name);
544         if (p->rdata)
545                 free(p->rdata);
546         free_dns_rr(p->next);
547         free(p);
548 }
549
550 static void
551 free_dns_response(struct dns_response *p)
552 {
553         if (p == NULL)
554                 return;
555
556         free_dns_query(p->query);
557         free_dns_rr(p->answer);
558         free_dns_rr(p->authority);
559         free_dns_rr(p->additional);
560         free(p);
561 }
562
563 static int
564 count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type)
565 {
566         int n = 0;
567
568         while(p) {
569                 if (p->class == class && p->type == type)
570                         n++;
571                 p = p->next;
572         }
573
574         return (n);
575 }
576
577 #endif /* !defined(HAVE_GETRRSETBYNAME) */
This page took 0.106873 seconds and 5 git commands to generate.