1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <errno.h>
21: #include <resolv.h>
22: #include <stdio.h>
23: #include <string.h>
24: #include <arpa/nameser.h>
25: #include <not-cancel.h>
26:
27: #include "nscd-client.h"
28: #include "nscd_proto.h"
29:
30: int __nss_not_use_nscd_hosts;
31:
32: static int nscd_gethst_r (const char *key, size_t keylen, request_type type,
33: struct hostent *resultbuf, char *buffer,
34: size_t buflen, struct hostent **result,
35: int *h_errnop) internal_function;
36:
37:
38: int
39: __nscd_gethostbyname_r (const char *name, struct hostent *resultbuf,
40: char *buffer, size_t buflen, struct hostent **result,
41: int *h_errnop)
42: {
43: request_type reqtype;
44:
45: reqtype = (_res.options & RES_USE_INET6) ? GETHOSTBYNAMEv6 : GETHOSTBYNAME;
46:
47: return nscd_gethst_r (name, strlen (name) + 1, reqtype, resultbuf,
48: buffer, buflen, result, h_errnop);
49: }
50:
51:
52: int
53: __nscd_gethostbyname2_r (const char *name, int af, struct hostent *resultbuf,
54: char *buffer, size_t buflen, struct hostent **result,
55: int *h_errnop)
56: {
57: request_type reqtype;
58:
59: reqtype = af == AF_INET6 ? GETHOSTBYNAMEv6 : GETHOSTBYNAME;
60:
61: return nscd_gethst_r (name, strlen (name) + 1, reqtype, resultbuf,
62: buffer, buflen, result, h_errnop);
63: }
64:
65:
66: int
67: __nscd_gethostbyaddr_r (const void *addr, socklen_t len, int type,
68: struct hostent *resultbuf, char *buffer, size_t buflen,
69: struct hostent **result, int *h_errnop)
70: {
71: request_type reqtype;
72:
73: if (!((len == INADDRSZ && type == AF_INET)
74: || (len == IN6ADDRSZ && type == AF_INET6)))
75:
76: return -1;
77:
78: reqtype = type == AF_INET6 ? GETHOSTBYADDRv6 : GETHOSTBYADDR;
79:
80: return nscd_gethst_r (addr, len, reqtype, resultbuf, buffer, buflen, result,
81: h_errnop);
82: }
83:
84:
85: libc_locked_map_ptr (, __hst_map_handle) attribute_hidden;
86:
87:
88:
89: libc_freeres_fn (hst_map_free)
90: {
91: if (__hst_map_handle.mapped != NO_MAPPING)
92: {
93: void *p = __hst_map_handle.mapped;
94: __hst_map_handle.mapped = NO_MAPPING;
95: free (p);
96: }
97: }
98:
99:
100: static int
101: internal_function
102: nscd_gethst_r (const char *key, size_t keylen, request_type type,
103: struct hostent *resultbuf, char *buffer, size_t buflen,
104: struct hostent **result, int *h_errnop)
105: {
106: int gc_cycle;
107: int nretries = 0;
108:
109:
110:
111: struct mapped_database *mapped;
112: mapped = __nscd_get_map_ref (GETFDHST, "hosts", &__hst_map_handle,
113: &gc_cycle);
114:
115: retry:;
116: const char *h_name = NULL;
117: const uint32_t *aliases_len = NULL;
118: const char *addr_list = NULL;
119: size_t addr_list_len = 0;
120: int retval = -1;
121: const char *recend = (const char *) ~UINTMAX_C (0);
122: int sock = -1;
123: hst_response_header hst_resp;
124: if (mapped != NO_MAPPING)
125: {
126:
127: struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
128: if (found != NULL)
129: {
130: h_name = (char *) (&found->data[0].hstdata + 1);
131: hst_resp = found->data[0].hstdata;
132: aliases_len = (uint32_t *) (h_name + hst_resp.h_name_len);
133: addr_list = ((char *) aliases_len
134: + hst_resp.h_aliases_cnt * sizeof (uint32_t));
135: addr_list_len = hst_resp.h_addr_list_cnt * INADDRSZ;
136: recend = (const char *) found->data + found->recsize;
137:
138:
139: if (mapped->head->gc_cycle != gc_cycle)
140: {
141: retval = -2;
142: goto out;
143: }
144:
145: #ifndef _STRING_ARCH_unaligned
146:
147:
148:
149:
150: if (((uintptr_t) aliases_len & (__alignof__ (*aliases_len) - 1))
151: != 0)
152: {
153: uint32_t *tmp = alloca (hst_resp.h_aliases_cnt
154: * sizeof (uint32_t));
155: aliases_len = memcpy (tmp, aliases_len,
156: hst_resp.h_aliases_cnt
157: * sizeof (uint32_t));
158: }
159: #endif
160: if (type != GETHOSTBYADDR && type != GETHOSTBYNAME)
161: {
162: if (hst_resp.h_length == INADDRSZ)
163: addr_list += addr_list_len;
164: addr_list_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ;
165: }
166: if (__builtin_expect ((const char *) addr_list + addr_list_len
167: > recend, 0))
168: goto out;
169: }
170: }
171:
172: if (h_name == NULL)
173: {
174: sock = __nscd_open_socket (key, keylen, type, &hst_resp,
175: sizeof (hst_resp));
176: if (sock == -1)
177: {
178: __nss_not_use_nscd_hosts = 1;
179: goto out;
180: }
181: }
182:
183:
184: *result = NULL;
185:
186: if (__builtin_expect (hst_resp.found == -1, 0))
187: {
188:
189: __nss_not_use_nscd_hosts = 1;
190: goto out_close;
191: }
192:
193: if (hst_resp.found == 1)
194: {
195: char *cp = buffer;
196: uintptr_t align1;
197: uintptr_t align2;
198: size_t total_len;
199: ssize_t cnt;
200: char *ignore;
201: int n;
202:
203:
204:
205:
206: align1 = ((__alignof__ (char *) - (cp - ((char *) 0)))
207: & (__alignof__ (char *) - 1));
208: align2 = ((__alignof__ (char *) - ((cp + align1 + hst_resp.h_name_len)
209: - ((char *) 0)))
210: & (__alignof__ (char *) - 1));
211: if (buflen < (align1 + hst_resp.h_name_len + align2
212: + ((hst_resp.h_aliases_cnt + hst_resp.h_addr_list_cnt
213: + 2)
214: * sizeof (char *))
215: + hst_resp.h_addr_list_cnt * (type == AF_INET
216: ? INADDRSZ : IN6ADDRSZ)))
217: {
218: no_room:
219: *h_errnop = NETDB_INTERNAL;
220: __set_errno (ERANGE);
221: retval = ERANGE;
222: goto out_close;
223: }
224: cp += align1;
225:
226:
227: resultbuf->h_aliases = (char **) cp;
228: cp += (hst_resp.h_aliases_cnt + 1) * sizeof (char *);
229: resultbuf->h_addr_list = (char **) cp;
230: cp += (hst_resp.h_addr_list_cnt + 1) * sizeof (char *);
231:
232: resultbuf->h_name = cp;
233: cp += hst_resp.h_name_len + align2;
234:
235: if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
236: {
237: resultbuf->h_addrtype = AF_INET;
238: resultbuf->h_length = INADDRSZ;
239: }
240: else
241: {
242: resultbuf->h_addrtype = AF_INET6;
243: resultbuf->h_length = IN6ADDRSZ;
244: }
245: for (cnt = 0; cnt < hst_resp.h_addr_list_cnt; ++cnt)
246: {
247: resultbuf->h_addr_list[cnt] = cp;
248: cp += resultbuf->h_length;
249: }
250: resultbuf->h_addr_list[cnt] = NULL;
251:
252: if (h_name == NULL)
253: {
254: struct iovec vec[4];
255:
256: vec[0].iov_base = resultbuf->h_name;
257: vec[0].iov_len = hst_resp.h_name_len;
258: total_len = hst_resp.h_name_len;
259: n = 1;
260:
261: if (hst_resp.h_aliases_cnt > 0)
262: {
263: aliases_len = alloca (hst_resp.h_aliases_cnt
264: * sizeof (uint32_t));
265: vec[n].iov_base = (void *) aliases_len;
266: vec[n].iov_len = hst_resp.h_aliases_cnt * sizeof (uint32_t);
267:
268: total_len += hst_resp.h_aliases_cnt * sizeof (uint32_t);
269: ++n;
270: }
271:
272: if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
273: {
274: vec[n].iov_base = resultbuf->h_addr_list[0];
275: vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
276:
277: total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
278:
279: ++n;
280: }
281: else
282: {
283: if (hst_resp.h_length == INADDRSZ)
284: {
285: ignore = alloca (hst_resp.h_addr_list_cnt * INADDRSZ);
286: vec[n].iov_base = ignore;
287: vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
288:
289: total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
290:
291: ++n;
292: }
293:
294: vec[n].iov_base = resultbuf->h_addr_list[0];
295: vec[n].iov_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ;
296:
297: total_len += hst_resp.h_addr_list_cnt * IN6ADDRSZ;
298:
299: ++n;
300: }
301:
302: if ((size_t) __readvall (sock, vec, n) != total_len)
303: goto out_close;
304: }
305: else
306: {
307: memcpy (resultbuf->h_name, h_name, hst_resp.h_name_len);
308: memcpy (resultbuf->h_addr_list[0], addr_list, addr_list_len);
309: }
310:
311:
312: total_len = 0;
313: for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt)
314: {
315: resultbuf->h_aliases[cnt] = cp;
316: cp += aliases_len[cnt];
317: total_len += aliases_len[cnt];
318: }
319: resultbuf->h_aliases[cnt] = NULL;
320:
321: if (__builtin_expect ((const char *) addr_list + addr_list_len
322: + total_len > recend, 0))
323: {
324:
325:
326: if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
327: retval = -2;
328: goto out_close;
329: }
330:
331: if (__builtin_expect (cp > buffer + buflen, 0))
332: {
333:
334:
335: if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
336: {
337: retval = -2;
338: goto out_close;
339: }
340: goto no_room;
341: }
342:
343:
344: if (addr_list == NULL)
345: {
346: if (total_len == 0
347: || ((size_t) __readall (sock, resultbuf->h_aliases[0], total_len)
348: == total_len))
349: {
350: retval = 0;
351: *result = resultbuf;
352: }
353: }
354: else
355: {
356: memcpy (resultbuf->h_aliases[0],
357: (const char *) addr_list + addr_list_len, total_len);
358:
359:
360: if (resultbuf->h_name[hst_resp.h_name_len - 1] != '\0'
361: || ({for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt)
362: if (resultbuf->h_aliases[cnt][aliases_len[cnt] - 1]
363: != '\0')
364: break;
365: cnt < hst_resp.h_aliases_cnt; }))
366: {
367:
368: if (mapped->head->gc_cycle != gc_cycle)
369: retval = -2;
370: goto out_close;
371: }
372:
373: retval = 0;
374: *result = resultbuf;
375: }
376: }
377: else
378: {
379:
380: *h_errnop = hst_resp.error;
381:
382:
383: __set_errno (0);
384:
385: retval = 0;
386: }
387:
388: out_close:
389: if (sock != -1)
390: close_not_cancel_no_status (sock);
391: out:
392: if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
393: {
394:
395:
396:
397: if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
398: {
399:
400: if (atomic_decrement_val (&mapped->counter) == 0)
401: __nscd_unmap (mapped);
402: mapped = NO_MAPPING;
403: }
404:
405: if (retval != -1)
406: goto retry;
407: }
408:
409: return retval;
410: }