Merge branch 'master' of ssh://gnunet.org/gnunet
[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
33 #include "nss_gns_query.h"
34
35 #include <arpa/inet.h>
36
37 /** macro to align idx to 32bit boundary */
38 #define ALIGN(idx) do { \
39   if (idx % sizeof(void*)) \
40     idx += (sizeof(void*) - idx % sizeof(void*)); /* Align on 32 bit boundary */ \
41 } while(0)
42
43
44 /**
45  * The gethostbyname hook executed by nsswitch
46  *
47  * @param name the name to resolve
48  * @param af the address family to resolve
49  * @param result the result hostent
50  * @param buffer the result buffer
51  * @param buflen length of the buffer
52  * @param errnop idk
53  * @param h_errnop idk
54  * @return a nss_status code
55  */
56 enum nss_status
57 _nss_gns_gethostbyname2_r(const char *name,
58                           int af,
59                           struct hostent *result,
60                           char *buffer,
61                           size_t buflen,
62                           int *errnop,
63                           int *h_errnop)
64 {
65   struct userdata u;
66   enum nss_status status = NSS_STATUS_UNAVAIL;
67   int i;
68   size_t address_length;
69   size_t l;
70   size_t idx;
71   size_t astart;
72
73   if (af == AF_UNSPEC)
74 #ifdef NSS_IPV6_ONLY
75     af = AF_INET6;
76 #else
77   af = AF_INET;
78 #endif
79
80 #ifdef NSS_IPV4_ONLY
81   if (af != AF_INET)
82 #elif NSS_IPV6_ONLY
83   if (af != AF_INET6)
84 #else
85   if ( (af != AF_INET) &&
86        (af != AF_INET6) )
87 #endif
88   {
89     *errnop = EINVAL;
90     *h_errnop = NO_RECOVERY;
91
92     goto finish;
93   }
94
95   address_length = (af == AF_INET) ? sizeof(ipv4_address_t) : sizeof(ipv6_address_t);
96   if (buflen <
97       sizeof(char*)+    /* alias names */
98       strlen(name)+1)
99   {   /* official name */
100     *errnop = ERANGE;
101     *h_errnop = NO_RECOVERY;
102     status = NSS_STATUS_TRYAGAIN;
103
104     goto finish;
105   }
106   u.count = 0;
107   u.data_len = 0;
108   i = gns_resolve_name (af,
109                         name,
110                         &u);
111   if (-3 == i)
112   {
113     status = NSS_STATUS_NOTFOUND;
114     goto finish;
115   }
116   if (-2 == i)
117   {
118     status = NSS_STATUS_UNAVAIL;
119     goto finish;
120   }
121   if ( (-1 == i) ||
122        (u.count == 0) )
123   {
124     *errnop = ETIMEDOUT;
125     *h_errnop = HOST_NOT_FOUND;
126     status = NSS_STATUS_NOTFOUND;
127     goto finish;
128   }
129   /* Alias names */
130   *((char**) buffer) = NULL;
131   result->h_aliases = (char**) buffer;
132   idx = sizeof(char*);
133
134   /* Official name */
135   strcpy (buffer+idx,
136           name);
137   result->h_name = buffer+idx;
138   idx += strlen (name)+1;
139
140   ALIGN(idx);
141
142   result->h_addrtype = af;
143   result->h_length = address_length;
144
145   /* Check if there's enough space for the addresses */
146   if (buflen < idx+u.data_len+sizeof(char*)*(u.count+1))
147   {
148     *errnop = ERANGE;
149     *h_errnop = NO_RECOVERY;
150     status = NSS_STATUS_TRYAGAIN;
151     goto finish;
152   }
153     /* Addresses */
154   astart = idx;
155   l = u.count*address_length;
156   if (0 != l)
157     memcpy (buffer+astart,
158             &u.data,
159             l);
160   /* address_length is a multiple of 32bits, so idx is still aligned
161    * correctly */
162   idx += l;
163
164   /* Address array address_length is always a multiple of 32bits */
165   for (i = 0; i < u.count; i++)
166     ((char**) (buffer+idx))[i] = buffer+astart+address_length*i;
167   ((char**) (buffer+idx))[i] = NULL;
168   result->h_addr_list = (char**) (buffer+idx);
169
170   status = NSS_STATUS_SUCCESS;
171
172 finish:
173   return status;
174 }
175
176
177 /**
178  * The gethostbyname hook executed by nsswitch
179  *
180  * @param name the name to resolve
181  * @param result the result hostent
182  * @param buffer the result buffer
183  * @param buflen length of the buffer
184  * @param errnop[out] the low-level error code to return to the application
185  * @param h_errnop idk
186  * @return a nss_status code
187  */
188 enum nss_status
189 _nss_gns_gethostbyname_r (const char *name,
190                           struct hostent *result,
191                           char *buffer,
192                           size_t buflen,
193                           int *errnop,
194                           int *h_errnop)
195 {
196   return _nss_gns_gethostbyname2_r (name,
197                                     AF_UNSPEC,
198                                     result,
199                                     buffer,
200                                     buflen,
201                                     errnop,
202                                     h_errnop);
203 }
204
205
206 /**
207  * The gethostbyaddr hook executed by nsswitch
208  * We can't do this so we always return NSS_STATUS_UNAVAIL
209  *
210  * @param addr the address to resolve
211  * @param len the length of the address
212  * @param af the address family of the address
213  * @param result the result hostent
214  * @param buffer the result buffer
215  * @param buflen length of the buffer
216  * @param errnop[out] the low-level error code to return to the application
217  * @param h_errnop idk
218  * @return NSS_STATUS_UNAVAIL
219  */
220 enum nss_status
221 _nss_gns_gethostbyaddr_r (const void* addr,
222                           int len,
223                           int af,
224                           struct hostent *result,
225                           char *buffer,
226                           size_t buflen,
227                           int *errnop,
228                           int *h_errnop)
229 {
230   *errnop = EINVAL;
231   *h_errnop = NO_RECOVERY;
232   //NOTE we allow to leak this into DNS so no NOTFOUND
233   return NSS_STATUS_UNAVAIL;
234 }