]> git.ipfire.org Git - thirdparty/glibc.git/blob - nscd/nscd_gethst_r.c
Update.
[thirdparty/glibc.git] / nscd / nscd_gethst_r.c
1 /* Copyright (C) 1998-2002, 2003, 2004 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
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 <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <arpa/nameser.h>
29 #include <sys/socket.h>
30 #include <sys/uio.h>
31 #include <sys/un.h>
32 #include <not-cancel.h>
33
34 #include "nscd-client.h"
35 #include "nscd_proto.h"
36
37 int __nss_not_use_nscd_hosts;
38
39 static int nscd_gethst_r (const char *key, size_t keylen, request_type type,
40 struct hostent *resultbuf, char *buffer,
41 size_t buflen, struct hostent **result,
42 int *h_errnop) internal_function;
43
44
45 int
46 __nscd_gethostbyname_r (const char *name, struct hostent *resultbuf,
47 char *buffer, size_t buflen, struct hostent **result,
48 int *h_errnop)
49 {
50 request_type reqtype;
51
52 reqtype = (_res.options & RES_USE_INET6) ? GETHOSTBYNAMEv6 : GETHOSTBYNAME;
53
54 return nscd_gethst_r (name, strlen (name) + 1, reqtype, resultbuf,
55 buffer, buflen, result, h_errnop);
56 }
57
58
59 int
60 __nscd_gethostbyname2_r (const char *name, int af, struct hostent *resultbuf,
61 char *buffer, size_t buflen, struct hostent **result,
62 int *h_errnop)
63 {
64 request_type reqtype;
65
66 reqtype = af == AF_INET6 ? GETHOSTBYNAMEv6 : GETHOSTBYNAME;
67
68 return nscd_gethst_r (name, strlen (name) + 1, reqtype, resultbuf,
69 buffer, buflen, result, h_errnop);
70 }
71
72
73 int
74 __nscd_gethostbyaddr_r (const void *addr, socklen_t len, int type,
75 struct hostent *resultbuf, char *buffer, size_t buflen,
76 struct hostent **result, int *h_errnop)
77 {
78 request_type reqtype;
79
80 if (!((len == INADDRSZ && type == AF_INET)
81 || (len == IN6ADDRSZ && type == AF_INET6)))
82 /* LEN and TYPE do not match. */
83 return -1;
84
85 reqtype = type == AF_INET6 ? GETHOSTBYADDRv6 : GETHOSTBYADDR;
86
87 return nscd_gethst_r (addr, len, reqtype, resultbuf, buffer, buflen, result,
88 h_errnop);
89 }
90
91
92 /* Create a socket connected to a name. */
93 int
94 __nscd_open_socket (const char *key, size_t keylen, request_type type,
95 void *response, size_t responselen)
96 {
97 struct sockaddr_un addr;
98 int sock;
99 int saved_errno = errno;
100
101 sock = __socket (PF_UNIX, SOCK_STREAM, 0);
102 if (sock < 0)
103 {
104 __set_errno (saved_errno);
105 return -1;
106 }
107
108 addr.sun_family = AF_UNIX;
109 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
110 if (__connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
111 {
112 __set_errno (saved_errno);
113 goto out;
114 }
115
116 request_header req;
117 req.version = NSCD_VERSION;
118 req.type = type;
119 req.key_len = keylen;
120
121 struct iovec vec[2];
122 vec[0].iov_base = &req;
123 vec[0].iov_len = sizeof (request_header);
124 vec[1].iov_base = (void *) key;
125 vec[1].iov_len = keylen;
126
127 ssize_t nbytes = TEMP_FAILURE_RETRY (__writev (sock, vec, 2));
128 if (nbytes != (ssize_t) (sizeof (request_header) + keylen))
129 {
130 out:
131 close_not_cancel_no_status (sock);
132 sock = -1;
133 }
134 else
135 {
136 nbytes = TEMP_FAILURE_RETRY (__read (sock, response, responselen));
137 if (nbytes != (ssize_t) responselen)
138 goto out;
139 }
140
141 return sock;
142 }
143
144
145 static int
146 internal_function
147 nscd_gethst_r (const char *key, size_t keylen, request_type type,
148 struct hostent *resultbuf, char *buffer, size_t buflen,
149 struct hostent **result, int *h_errnop)
150 {
151 hst_response_header hst_resp;
152 int sock = __nscd_open_socket (key, keylen, type, &hst_resp,
153 sizeof (hst_resp));
154 if (sock == -1)
155 {
156 __nss_not_use_nscd_hosts = 1;
157 return -1;
158 }
159
160 /* No value found so far. */
161 int retval = -1;
162 *result = NULL;
163
164 if (hst_resp.found == -1)
165 {
166 /* The daemon does not cache this database. */
167 __nss_not_use_nscd_hosts = 1;
168 goto out;
169 }
170
171 if (hst_resp.found == 1)
172 {
173 struct iovec vec[4];
174 uint32_t *aliases_len;
175 char *cp = buffer;
176 uintptr_t align1;
177 uintptr_t align2;
178 size_t total_len;
179 ssize_t cnt;
180 char *ignore;
181 int n;
182
183 /* A first check whether the buffer is sufficiently large is possible. */
184 /* Now allocate the buffer the array for the group members. We must
185 align the pointer and the base of the h_addr_list pointers. */
186 align1 = ((__alignof__ (char *) - (cp - ((char *) 0)))
187 & (__alignof__ (char *) - 1));
188 align2 = ((__alignof__ (char *) - ((cp + align1 + hst_resp.h_name_len)
189 - ((char *) 0)))
190 & (__alignof__ (char *) - 1));
191 if (buflen < (align1 + hst_resp.h_name_len + align2
192 + ((hst_resp.h_aliases_cnt + hst_resp.h_addr_list_cnt + 2)
193 * sizeof (char *))
194 + hst_resp.h_addr_list_cnt * (type == AF_INET
195 ? INADDRSZ : IN6ADDRSZ)))
196 {
197 no_room:
198 __set_errno (ERANGE);
199 retval = ERANGE;
200 goto out;
201 }
202 cp += align1;
203
204 /* Prepare the result as far as we can. */
205 resultbuf->h_aliases = (char **) cp;
206 cp += (hst_resp.h_aliases_cnt + 1) * sizeof (char *);
207 resultbuf->h_addr_list = (char **) cp;
208 cp += (hst_resp.h_addr_list_cnt + 1) * sizeof (char *);
209
210 resultbuf->h_name = cp;
211 cp += hst_resp.h_name_len + align2;
212 vec[0].iov_base = resultbuf->h_name;
213 vec[0].iov_len = hst_resp.h_name_len;
214
215 aliases_len = alloca (hst_resp.h_aliases_cnt * sizeof (uint32_t));
216 vec[1].iov_base = aliases_len;
217 vec[1].iov_len = hst_resp.h_aliases_cnt * sizeof (uint32_t);
218
219 total_len = (hst_resp.h_name_len
220 + hst_resp.h_aliases_cnt * sizeof (uint32_t));
221
222 n = 2;
223 if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
224 {
225 vec[2].iov_base = cp;
226 vec[2].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
227
228 for (cnt = 0; cnt < hst_resp.h_addr_list_cnt; ++cnt)
229 {
230 resultbuf->h_addr_list[cnt] = cp;
231 cp += INADDRSZ;
232 }
233
234 resultbuf->h_addrtype = AF_INET;
235 resultbuf->h_length = INADDRSZ;
236
237 total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
238
239 n = 3;
240 }
241 else
242 {
243 if (hst_resp.h_length == INADDRSZ)
244 {
245 ignore = alloca (hst_resp.h_addr_list_cnt * INADDRSZ);
246 vec[2].iov_base = ignore;
247 vec[2].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
248
249 total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
250
251 n = 3;
252 }
253
254 vec[n].iov_base = cp;
255 vec[n].iov_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ;
256
257 for (cnt = 0; cnt < hst_resp.h_addr_list_cnt; ++cnt)
258 {
259 resultbuf->h_addr_list[cnt] = cp;
260 cp += IN6ADDRSZ;
261 }
262
263 resultbuf->h_addrtype = AF_INET6;
264 resultbuf->h_length = IN6ADDRSZ;
265
266 total_len += hst_resp.h_addr_list_cnt * IN6ADDRSZ;
267
268 ++n;
269 }
270 resultbuf->h_addr_list[cnt] = NULL;
271
272 if ((size_t) TEMP_FAILURE_RETRY (__readv (sock, vec, n)) != total_len)
273 goto out;
274
275 /* Now we also can read the aliases. */
276 total_len = 0;
277 for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt)
278 {
279 resultbuf->h_aliases[cnt] = cp;
280 cp += aliases_len[cnt];
281 total_len += aliases_len[cnt];
282 }
283 resultbuf->h_aliases[cnt] = NULL;
284
285 /* See whether this would exceed the buffer capacity. */
286 if (cp > buffer + buflen)
287 goto no_room;
288
289 /* And finally read the aliases. */
290 if ((size_t) TEMP_FAILURE_RETRY (__read (sock, resultbuf->h_aliases[0],
291 total_len)) == total_len)
292 {
293 retval = 0;
294 *result = resultbuf;
295 }
296 }
297 else
298 {
299 /* Store the error number. */
300 *h_errnop = hst_resp.error;
301
302 /* The `errno' to some value != ERANGE. */
303 __set_errno (ENOENT);
304 /* Even though we have not found anything, the result is zero. */
305 retval = 0;
306 }
307
308 out:
309 __close (sock);
310
311 return retval;
312 }