e5b38f5e7c28be952755c242f2c2cd74b0de0777
[kopensolaris-gnu/glibc.git] / resolv / nss_dns / dns-canon.c
1 /* Copyright (C) 2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <errno.h>
21 #include <netdb.h>
22 #include <resolv.h>
23 #include <stdlib.h>
24 #include <arpa/nameser.h>
25 #include <nsswitch.h>
26
27
28 #if PACKETSZ > 65536
29 # define MAXPACKET      PACKETSZ
30 #else
31 # define MAXPACKET      65536
32 #endif
33
34
35 /* We need this time later.  */
36 typedef union querybuf
37 {
38   HEADER hdr;
39   unsigned char buf[MAXPACKET];
40 } querybuf;
41
42
43 enum nss_status
44 _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
45                          char **result,int *errnop, int *h_errnop)
46 {
47   /* Just an alibi buffer, res_nquery will allocate a real buffer for
48      us.  */
49   unsigned char buf[20];
50   union
51   {
52     querybuf *buf;
53     unsigned char *ptr;
54   } ansp = { .ptr = buf };
55   enum nss_status status;
56
57   int r = __libc_res_nquery (&_res, name, ns_c_in, ns_t_cname,
58                              buf, sizeof (buf), &ansp.ptr);
59   if (r > 0)
60     {
61       /* We need to decode the response.  Just one question record.
62          And if we got no answers we bail out, too.  */
63       if (ansp.buf->hdr.qdcount != htons (1)
64           || ansp.buf->hdr.ancount == 0)
65         goto unavail;
66
67       /* Beginning and end of the buffer with query, answer, and the
68          rest.  */
69       unsigned char *ptr = &ansp.buf->buf[sizeof (HEADER)];
70       unsigned char *endptr = ansp.ptr + r;
71
72       /* Skip over the query.  This is the name, type, and class.  */
73       int s = __dn_skipname (ptr, endptr);
74       if (s < 0)
75         goto unavail;
76
77       /* Skip over the name and the two 16-bit values containing type
78          and class.  */
79       ptr += s + 2 * sizeof (uint16_t);
80
81       /* Now the reply.  First again the name from the query, then
82          type, class, TTL, and the length of the RDATA.  */
83       s = __dn_skipname (ptr, endptr);
84       if (s < 0)
85         goto unavail;
86
87       ptr += s;
88
89       /* Check whether type and class match.  */
90       if (*(uint16_t *) ptr != htons (ns_t_cname))
91         goto unavail;
92
93       ptr += sizeof (uint16_t);
94       if (*(uint16_t *) ptr != htons (ns_c_in))
95         goto unavail;
96
97       /* Also skip over the TTL and rdata length.  */
98       ptr += sizeof (uint16_t) + sizeof (uint32_t) + sizeof (int16_t);
99
100       /* Now the name we are looking for.  */
101       s = __dn_expand (ansp.buf->buf, endptr, ptr, buffer, buflen);
102       if (s < 0)
103         {
104           if (errno != EMSGSIZE)
105             goto unavail;
106
107           /* The buffer is too small.  */
108           *errnop = ERANGE;
109           status = NSS_STATUS_TRYAGAIN;
110           h_errno = NETDB_INTERNAL;
111         }
112       else
113         {
114           /* Success.  */
115           *result = buffer;
116           status = NSS_STATUS_SUCCESS;
117         }
118     }
119   else if (h_errno == TRY_AGAIN)
120     {
121     again:
122       status = NSS_STATUS_TRYAGAIN;
123       *errnop = errno;
124     }
125   else
126     {
127     unavail:
128       status = NSS_STATUS_UNAVAIL;
129       *errnop = errno;
130     }
131   *h_errnop = h_errno;
132
133   if (ansp.ptr != buf)
134     free (ansp.ptr);
135
136   return status;
137 }