REST: nothing triggers rest
[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) : sizeof(ipv6_address_t);
97   if (buflen <
98       sizeof(char*) +     /* alias names */
99       strlen (name) + 1)
100   {   /* official name */
101     *errnop = ERANGE;
102     *h_errnop = NO_RECOVERY;
103     status = NSS_STATUS_TRYAGAIN;
104
105     goto finish;
106   }
107   u.count = 0;
108   u.data_len = 0;
109   i = gns_resolve_name (af,
110                         name,
111                         &u);
112   if (-1 == i)
113   {
114     *errnop = errno;
115     status = NSS_STATUS_UNAVAIL;
116     *h_errnop = NO_RECOVERY;
117     goto finish;
118   }
119   if (-2 == i)
120   {
121     *errnop = ENOENT;
122     *h_errnop = NO_RECOVERY;
123     status = NSS_STATUS_UNAVAIL;
124     goto finish;
125   }
126   if (-3 == i)
127   {
128     *errnop = ETIMEDOUT;
129     *h_errnop = HOST_NOT_FOUND;
130     status = NSS_STATUS_NOTFOUND;
131     goto finish;
132   }
133   if (0 == u.count) 
134   {
135     *errnop = 0; /* success */ 
136     *h_errnop = NO_DATA; /* success */
137     status = NSS_STATUS_NOTFOUND;
138     goto finish;
139   }
140   /* Alias names */
141   *((char**) buffer) = NULL;
142   result->h_aliases = (char**) buffer;
143   idx = sizeof(char*);
144
145   /* Official name */
146   strcpy (buffer+idx,
147           name);
148   result->h_name = buffer+idx;
149   idx += strlen (name)+1;
150
151   ALIGN(idx);
152
153   result->h_addrtype = af;
154   result->h_length = address_length;
155
156   /* Check if there's enough space for the addresses */
157   if (buflen < idx+u.data_len+sizeof(char*)*(u.count+1))
158   {
159     *errnop = ERANGE;
160     *h_errnop = NO_RECOVERY;
161     status = NSS_STATUS_TRYAGAIN;
162     goto finish;
163   }
164     /* Addresses */
165   astart = idx;
166   l = u.count*address_length;
167   if (0 != l)
168     memcpy (buffer+astart,
169             &u.data,
170             l);
171   /* address_length is a multiple of 32bits, so idx is still aligned
172    * correctly */
173   idx += l;
174
175   /* Address array address_length is always a multiple of 32bits */
176   for (i = 0; i < u.count; i++)
177     ((char**) (buffer+idx))[i] = buffer+astart+address_length*i;
178   ((char**) (buffer+idx))[i] = NULL;
179   result->h_addr_list = (char**) (buffer+idx);
180
181   status = NSS_STATUS_SUCCESS;
182
183 finish:
184   return status;
185 }
186
187
188 /**
189  * The gethostbyname hook executed by nsswitch
190  *
191  * @param name the name to resolve
192  * @param result the result hostent
193  * @param buffer the result buffer
194  * @param buflen length of the buffer
195  * @param errnop[out] the low-level error code to return to the application
196  * @param h_errnop idk
197  * @return a nss_status code
198  */
199 enum nss_status
200 _nss_gns_gethostbyname_r (const char *name,
201                           struct hostent *result,
202                           char *buffer,
203                           size_t buflen,
204                           int *errnop,
205                           int *h_errnop)
206 {
207   return _nss_gns_gethostbyname2_r (name,
208                                     AF_UNSPEC,
209                                     result,
210                                     buffer,
211                                     buflen,
212                                     errnop,
213                                     h_errnop);
214 }
215
216
217 /**
218  * The gethostbyaddr hook executed by nsswitch
219  * We can't do this so we always return NSS_STATUS_UNAVAIL
220  *
221  * @param addr the address to resolve
222  * @param len the length of the address
223  * @param af the address family of the address
224  * @param result the result hostent
225  * @param buffer the result buffer
226  * @param buflen length of the buffer
227  * @param errnop[out] the low-level error code to return to the application
228  * @param h_errnop idk
229  * @return NSS_STATUS_UNAVAIL
230  */
231 enum nss_status
232 _nss_gns_gethostbyaddr_r (const void* addr,
233                           int len,
234                           int af,
235                           struct hostent *result,
236                           char *buffer,
237                           size_t buflen,
238                           int *errnop,
239                           int *h_errnop)
240 {
241   (void) addr;
242   (void) len;
243   (void) af;
244   (void) result;
245   (void) buffer;
246   (void) buflen;
247   *errnop = EINVAL;
248   *h_errnop = NO_RECOVERY;
249   /* NOTE we allow to leak this into DNS so no NOTFOUND */
250   return NSS_STATUS_UNAVAIL;
251 }