-remove debug message
[oweals/gnunet.git] / src / gns / nss / nss_gns.c
1 /***
2     This file is part of nss-gns.
3
4     Parts taken from: nss.c in nss-mdns
5
6     nss-mdns is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published
8     by the Free Software Foundation; either version 3 of the License,
9     or (at your option) any later version.
10
11     nss-mdns is distributed in the hope that it will be useful, but1
12     WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     General Public License for more details.
15
16     You should have received a copy of the GNU Lesser General Public License
17     along with nss-mdns; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19     USA.
20  ***/
21
22 #include <gnunet_config.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <netdb.h>
28 #include <sys/socket.h>
29 #include <nss.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <errno.h>
33
34 #include "nss_gns_query.h"
35
36 #include <arpa/inet.h>
37
38 /** macro to align idx to 32bit boundary */
39 #define ALIGN(idx) do { \
40     if (idx % sizeof(void*)) \
41       idx += (sizeof(void*) - idx % sizeof(void*)); /* Align on 32 bit boundary */ \
42 } while (0)
43
44
45 /**
46  * The gethostbyname hook executed by nsswitch
47  *
48  * @param name the name to resolve
49  * @param af the address family to resolve
50  * @param result the result hostent
51  * @param buffer the result buffer
52  * @param buflen length of the buffer
53  * @param errnop idk
54  * @param h_errnop idk
55  * @return a nss_status code
56  */
57 enum nss_status
58 _nss_gns_gethostbyname2_r (const char *name,
59                            int af,
60                            struct hostent *result,
61                            char *buffer,
62                            size_t buflen,
63                            int *errnop,
64                            int *h_errnop)
65 {
66   struct userdata u;
67   enum nss_status status = NSS_STATUS_UNAVAIL;
68   int i;
69   size_t address_length;
70   size_t l;
71   size_t idx;
72   size_t astart;
73
74   if (af == AF_UNSPEC)
75 #ifdef NSS_IPV6_ONLY
76     af = AF_INET6;
77 #else
78     af = AF_INET;
79 #endif
80
81 #ifdef NSS_IPV4_ONLY
82   if (af != AF_INET)
83 #elif NSS_IPV6_ONLY
84   if (af != AF_INET6)
85 #else
86   if ((af != AF_INET) &&
87       (af != AF_INET6))
88 #endif
89   {
90     *errnop = EINVAL;
91     *h_errnop = NO_RECOVERY;
92
93     goto finish;
94   }
95
96   address_length = (af == AF_INET) ? sizeof(ipv4_address_t) :
97                    sizeof(ipv6_address_t);
98   if (buflen <
99       sizeof(char*)       /* alias names */
100       + strlen (name) + 1)
101   {   /* official name */
102     *errnop = ERANGE;
103     *h_errnop = NO_RECOVERY;
104     status = NSS_STATUS_TRYAGAIN;
105
106     goto finish;
107   }
108   u.count = 0;
109   u.data_len = 0;
110   i = gns_resolve_name (af,
111                         name,
112                         &u);
113   if (-1 == i)
114   {
115     *errnop = errno;
116     status = NSS_STATUS_UNAVAIL;
117     *h_errnop = NO_RECOVERY;
118     goto finish;
119   }
120   if (-2 == i)
121   {
122     *errnop = ENOENT;
123     *h_errnop = NO_RECOVERY;
124     status = NSS_STATUS_UNAVAIL;
125     goto finish;
126   }
127   if (-3 == i)
128   {
129     *errnop = ETIMEDOUT;
130     *h_errnop = HOST_NOT_FOUND;
131     status = NSS_STATUS_NOTFOUND;
132     goto finish;
133   }
134   if (0 == u.count)
135   {
136     *errnop = 0;   /* success */
137     *h_errnop = NO_DATA;   /* success */
138     status = NSS_STATUS_NOTFOUND;
139     goto finish;
140   }
141   /* Alias names */
142   *((char **) buffer) = NULL;
143   result->h_aliases = (char **) buffer;
144   idx = sizeof(char*);
145
146   /* Official name */
147   strcpy (buffer + idx,
148           name);
149   result->h_name = buffer + idx;
150   idx += strlen (name) + 1;
151
152   ALIGN (idx);
153
154   result->h_addrtype = af;
155   result->h_length = address_length;
156
157   /* Check if there's enough space for the addresses */
158   if (buflen < idx + u.data_len + sizeof(char*) * (u.count + 1))
159   {
160     *errnop = ERANGE;
161     *h_errnop = NO_RECOVERY;
162     status = NSS_STATUS_TRYAGAIN;
163     goto finish;
164   }
165   /* Addresses */
166   astart = idx;
167   l = u.count * address_length;
168   if (0 != l)
169     memcpy (buffer + astart,
170             &u.data,
171             l);
172   /* address_length is a multiple of 32bits, so idx is still aligned
173    * correctly */
174   idx += l;
175
176   /* Address array address_length is always a multiple of 32bits */
177   for (i = 0; i < u.count; i++)
178     ((char **) (buffer + idx))[i] = buffer + astart + address_length * i;
179   ((char **) (buffer + idx))[i] = NULL;
180   result->h_addr_list = (char **) (buffer + idx);
181
182   status = NSS_STATUS_SUCCESS;
183
184 finish:
185   return status;
186 }
187
188
189 /**
190  * The gethostbyname hook executed by nsswitch
191  *
192  * @param name the name to resolve
193  * @param result the result hostent
194  * @param buffer the result buffer
195  * @param buflen length of the buffer
196  * @param errnop[out] the low-level error code to return to the application
197  * @param h_errnop idk
198  * @return a nss_status code
199  */
200 enum nss_status
201 _nss_gns_gethostbyname_r (const char *name,
202                           struct hostent *result,
203                           char *buffer,
204                           size_t buflen,
205                           int *errnop,
206                           int *h_errnop)
207 {
208   return _nss_gns_gethostbyname2_r (name,
209                                     AF_UNSPEC,
210                                     result,
211                                     buffer,
212                                     buflen,
213                                     errnop,
214                                     h_errnop);
215 }
216
217
218 /**
219  * The gethostbyaddr hook executed by nsswitch
220  * We can't do this so we always return NSS_STATUS_UNAVAIL
221  *
222  * @param addr the address to resolve
223  * @param len the length of the address
224  * @param af the address family of the address
225  * @param result the result hostent
226  * @param buffer the result buffer
227  * @param buflen length of the buffer
228  * @param errnop[out] the low-level error code to return to the application
229  * @param h_errnop idk
230  * @return NSS_STATUS_UNAVAIL
231  */
232 enum nss_status
233 _nss_gns_gethostbyaddr_r (const void*addr,
234                           int len,
235                           int af,
236                           struct hostent *result,
237                           char *buffer,
238                           size_t buflen,
239                           int *errnop,
240                           int *h_errnop)
241 {
242   (void) addr;
243   (void) len;
244   (void) af;
245   (void) result;
246   (void) buffer;
247   (void) buflen;
248   *errnop = EINVAL;
249   *h_errnop = NO_RECOVERY;
250   /* NOTE we allow to leak this into DNS so no NOTFOUND */
251   return NSS_STATUS_UNAVAIL;
252 }