]>
Commit | Line | Data |
---|---|---|
04277e02 | 1 | /* Copyright (C) 1996-2019 Free Software Foundation, Inc. |
6259ec0d | 2 | This file is part of the GNU C Library. |
1e275b9e | 3 | Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. |
6259ec0d UD |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
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. | |
6259ec0d UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
6259ec0d | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
6259ec0d | 18 | |
1eb946b9 | 19 | #include <assert.h> |
6259ec0d UD |
20 | #include <nss.h> |
21 | #include <ctype.h> | |
6675b191 UD |
22 | /* The following is an ugly trick to avoid a prototype declaration for |
23 | _nss_nis_endgrent. */ | |
24 | #define _nss_nis_endhostent _nss_nis_endhostent_XXX | |
6259ec0d | 25 | #include <netdb.h> |
6675b191 | 26 | #undef _nss_nis_endhostent |
6259ec0d UD |
27 | #include <string.h> |
28 | #include <netinet/in.h> | |
29 | #include <arpa/inet.h> | |
b76e0659 | 30 | #include <resolv/resolv-internal.h> |
ec999b8e | 31 | #include <libc-lock.h> |
6259ec0d UD |
32 | #include <rpcsvc/yp.h> |
33 | #include <rpcsvc/ypclnt.h> | |
34 | ||
35 | #include "nss-nis.h" | |
36 | ||
37 | /* Get implementation for some internal functions. */ | |
cf29ffbe | 38 | #include <resolv/mapv4v6addr.h> |
6259ec0d UD |
39 | |
40 | #define ENTNAME hostent | |
41 | #define DATABASE "hosts" | |
42 | #define NEED_H_ERRNO | |
43 | ||
1e275b9e UD |
44 | #define EXTRA_ARGS , af, flags |
45 | #define EXTRA_ARGS_DECL , int af, int flags | |
46 | ||
6259ec0d UD |
47 | #define ENTDATA hostent_data |
48 | struct hostent_data | |
49 | { | |
50 | unsigned char host_addr[16]; /* IPv4 or IPv6 address. */ | |
51 | char *h_addr_ptrs[2]; /* Points to that and null terminator. */ | |
52 | }; | |
53 | ||
54 | #define TRAILING_LIST_MEMBER h_aliases | |
55 | #define TRAILING_LIST_SEPARATOR_P isspace | |
cf29ffbe | 56 | #include <nss/nss_files/files-parse.c> |
6259ec0d UD |
57 | LINE_PARSER |
58 | ("#", | |
59 | { | |
60 | char *addr; | |
61 | ||
62 | STRING_FIELD (addr, isspace, 1); | |
63 | ||
1eb946b9 UD |
64 | assert (af == AF_INET || af == AF_INET6 || af == AF_UNSPEC); |
65 | ||
6259ec0d | 66 | /* Parse address. */ |
1eb946b9 | 67 | if (af != AF_INET6 && inet_pton (AF_INET, addr, entdata->host_addr) > 0) |
1e275b9e | 68 | { |
1eb946b9 | 69 | assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC); |
1e275b9e | 70 | if (flags & AI_V4MAPPED) |
a682a1bf UD |
71 | { |
72 | map_v4v6_address ((char *) entdata->host_addr, | |
73 | (char *) entdata->host_addr); | |
74 | result->h_addrtype = AF_INET6; | |
75 | result->h_length = IN6ADDRSZ; | |
76 | } | |
1e275b9e | 77 | else |
a682a1bf UD |
78 | { |
79 | result->h_addrtype = AF_INET; | |
80 | result->h_length = INADDRSZ; | |
81 | } | |
1e275b9e | 82 | } |
1eb946b9 | 83 | else if (af != AF_INET |
a682a1bf | 84 | && inet_pton (AF_INET6, addr, entdata->host_addr) > 0) |
6259ec0d UD |
85 | { |
86 | result->h_addrtype = AF_INET6; | |
87 | result->h_length = IN6ADDRSZ; | |
88 | } | |
89 | else | |
1e275b9e UD |
90 | /* Illegal address: ignore line. */ |
91 | return 0; | |
6259ec0d UD |
92 | |
93 | /* Store a pointer to the address in the expected form. */ | |
701666b7 | 94 | entdata->h_addr_ptrs[0] = (char *) entdata->host_addr; |
6259ec0d UD |
95 | entdata->h_addr_ptrs[1] = NULL; |
96 | result->h_addr_list = entdata->h_addr_ptrs; | |
97 | ||
6259ec0d | 98 | STRING_FIELD (result->h_name, isspace, 1); |
1e275b9e UD |
99 | }) |
100 | ||
6259ec0d UD |
101 | |
102 | __libc_lock_define_initialized (static, lock) | |
103 | ||
104 | static bool_t new_start = 1; | |
105 | static char *oldkey = NULL; | |
106 | static int oldkeylen = 0; | |
107 | ||
1eb946b9 | 108 | |
6259ec0d | 109 | enum nss_status |
51eecc4a | 110 | _nss_nis_sethostent (int stayopen) |
6259ec0d UD |
111 | { |
112 | __libc_lock_lock (lock); | |
113 | ||
114 | new_start = 1; | |
115 | if (oldkey != NULL) | |
116 | { | |
117 | free (oldkey); | |
118 | oldkey = NULL; | |
119 | oldkeylen = 0; | |
120 | } | |
121 | ||
122 | __libc_lock_unlock (lock); | |
123 | ||
124 | return NSS_STATUS_SUCCESS; | |
125 | } | |
6675b191 UD |
126 | /* Make _nss_nis_endhostent an alias of _nss_nis_sethostent. We do this |
127 | even though the prototypes don't match. The argument of sethostent | |
128 | is used so this makes no difference. */ | |
129 | strong_alias (_nss_nis_sethostent, _nss_nis_endhostent) | |
6259ec0d | 130 | |
1eb946b9 | 131 | |
1e275b9e | 132 | /* The calling function always need to get a lock first. */ |
6259ec0d UD |
133 | static enum nss_status |
134 | internal_nis_gethostent_r (struct hostent *host, char *buffer, | |
1e275b9e UD |
135 | size_t buflen, int *errnop, int *h_errnop, |
136 | int af, int flags) | |
6259ec0d UD |
137 | { |
138 | char *domain; | |
a1ffb40e | 139 | if (__glibc_unlikely (yp_get_default_domain (&domain))) |
a334319f | 140 | return NSS_STATUS_UNAVAIL; |
0ecb606c | 141 | |
2f1687b9 UD |
142 | uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); |
143 | buffer += pad; | |
144 | ||
ab9a9ff8 | 145 | struct parser_data *data = (void *) buffer; |
a1ffb40e | 146 | if (__glibc_unlikely (buflen < sizeof *data + 1 + pad)) |
6259ec0d | 147 | { |
d71b808a | 148 | *errnop = ERANGE; |
6259ec0d UD |
149 | *h_errnop = NETDB_INTERNAL; |
150 | return NSS_STATUS_TRYAGAIN; | |
151 | } | |
2f1687b9 | 152 | buflen -= pad; |
6259ec0d UD |
153 | |
154 | /* Get the next entry until we found a correct one. */ | |
ab9a9ff8 UD |
155 | const size_t linebuflen = buffer + buflen - data->linebuffer; |
156 | int parse_res; | |
6259ec0d UD |
157 | do |
158 | { | |
ab9a9ff8 UD |
159 | char *result; |
160 | int len; | |
161 | char *outkey; | |
162 | int keylen; | |
163 | int yperr; | |
6259ec0d | 164 | if (new_start) |
a682a1bf | 165 | yperr = yp_first (domain, "hosts.byname", &outkey, &keylen, &result, |
ab9a9ff8 | 166 | &len); |
6259ec0d | 167 | else |
a682a1bf | 168 | yperr = yp_next (domain, "hosts.byname", oldkey, oldkeylen, &outkey, |
ab9a9ff8 | 169 | &keylen, &result, &len); |
6259ec0d | 170 | |
a1ffb40e | 171 | if (__glibc_unlikely (yperr != YPERR_SUCCESS)) |
a682a1bf | 172 | { |
ab9a9ff8 UD |
173 | enum nss_status retval = yperr2nss (yperr); |
174 | ||
6259ec0d UD |
175 | switch (retval) |
176 | { | |
177 | case NSS_STATUS_TRYAGAIN: | |
d71b808a | 178 | *errnop = errno; |
6259ec0d UD |
179 | *h_errnop = TRY_AGAIN; |
180 | break; | |
181 | case NSS_STATUS_NOTFOUND: | |
182 | *h_errnop = HOST_NOT_FOUND; | |
183 | break; | |
184 | default: | |
185 | *h_errnop = NO_RECOVERY; | |
186 | break; | |
187 | } | |
188 | return retval; | |
189 | } | |
190 | ||
a1ffb40e | 191 | if (__glibc_unlikely ((size_t) (len + 1) > linebuflen)) |
a682a1bf UD |
192 | { |
193 | free (result); | |
6259ec0d | 194 | *h_errnop = NETDB_INTERNAL; |
a682a1bf UD |
195 | *errnop = ERANGE; |
196 | return NSS_STATUS_TRYAGAIN; | |
197 | } | |
6259ec0d | 198 | |
ab9a9ff8 | 199 | char *p = strncpy (data->linebuffer, result, len); |
6259ec0d UD |
200 | data->linebuffer[len] = '\0'; |
201 | while (isspace (*p)) | |
202 | ++p; | |
203 | free (result); | |
204 | ||
1e275b9e | 205 | parse_res = parse_line (p, host, data, buflen, errnop, af, flags); |
a1ffb40e | 206 | if (__glibc_unlikely (parse_res == -1)) |
6259ec0d | 207 | { |
60c96635 | 208 | free (outkey); |
d71b808a UD |
209 | *h_errnop = NETDB_INTERNAL; |
210 | *errnop = ERANGE; | |
6259ec0d UD |
211 | return NSS_STATUS_TRYAGAIN; |
212 | } | |
213 | free (oldkey); | |
214 | oldkey = outkey; | |
215 | oldkeylen = keylen; | |
216 | new_start = 0; | |
217 | } | |
218 | while (!parse_res); | |
219 | ||
220 | *h_errnop = NETDB_SUCCESS; | |
221 | return NSS_STATUS_SUCCESS; | |
222 | } | |
223 | ||
1eb946b9 | 224 | |
1e275b9e | 225 | enum nss_status |
6259ec0d | 226 | _nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen, |
d71b808a | 227 | int *errnop, int *h_errnop) |
6259ec0d | 228 | { |
1e275b9e | 229 | enum nss_status status; |
6259ec0d UD |
230 | |
231 | __libc_lock_lock (lock); | |
232 | ||
1e275b9e | 233 | status = internal_nis_gethostent_r (host, buffer, buflen, errnop, h_errnop, |
b76e0659 FW |
234 | (res_use_inet6 () ? AF_INET6 : AF_INET), |
235 | (res_use_inet6 () ? AI_V4MAPPED : 0 )); | |
6259ec0d UD |
236 | |
237 | __libc_lock_unlock (lock); | |
238 | ||
239 | return status; | |
240 | } | |
241 | ||
1eb946b9 | 242 | |
1e275b9e UD |
243 | static enum nss_status |
244 | internal_gethostbyname2_r (const char *name, int af, struct hostent *host, | |
d71b808a | 245 | char *buffer, size_t buflen, int *errnop, |
1e275b9e | 246 | int *h_errnop, int flags) |
6259ec0d | 247 | { |
2f1687b9 UD |
248 | uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); |
249 | buffer += pad; | |
250 | ||
6259ec0d | 251 | struct parser_data *data = (void *) buffer; |
6259ec0d UD |
252 | |
253 | if (name == NULL) | |
254 | { | |
ac9f45cf | 255 | *errnop = EINVAL; |
6259ec0d UD |
256 | return NSS_STATUS_UNAVAIL; |
257 | } | |
258 | ||
ab9a9ff8 | 259 | char *domain; |
6259ec0d UD |
260 | if (yp_get_default_domain (&domain)) |
261 | return NSS_STATUS_UNAVAIL; | |
262 | ||
2f1687b9 | 263 | if (buflen < sizeof *data + 1 + pad) |
6259ec0d UD |
264 | { |
265 | *h_errnop = NETDB_INTERNAL; | |
d71b808a | 266 | *errnop = ERANGE; |
6259ec0d UD |
267 | return NSS_STATUS_TRYAGAIN; |
268 | } | |
2f1687b9 | 269 | buflen -= pad; |
cd897fe7 | 270 | |
ab9a9ff8 UD |
271 | /* Convert name to lowercase. */ |
272 | size_t namlen = strlen (name); | |
315eb1d8 AS |
273 | /* Limit name length to the maximum size of an RPC packet. */ |
274 | if (namlen > UDPMSGSIZE) | |
275 | { | |
276 | *errnop = ERANGE; | |
277 | return NSS_STATUS_UNAVAIL; | |
278 | } | |
279 | ||
ab9a9ff8 UD |
280 | char name2[namlen + 1]; |
281 | size_t i; | |
cd897fe7 | 282 | |
ab9a9ff8 UD |
283 | for (i = 0; i < namlen; ++i) |
284 | name2[i] = tolower (name[i]); | |
285 | name2[i] = '\0'; | |
cd897fe7 | 286 | |
ab9a9ff8 UD |
287 | char *result; |
288 | int len; | |
289 | int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len); | |
6259ec0d | 290 | |
a1ffb40e | 291 | if (__glibc_unlikely (yperr != YPERR_SUCCESS)) |
6259ec0d | 292 | { |
ab9a9ff8 UD |
293 | enum nss_status retval = yperr2nss (yperr); |
294 | ||
6259ec0d UD |
295 | if (retval == NSS_STATUS_TRYAGAIN) |
296 | { | |
297 | *h_errnop = TRY_AGAIN; | |
d71b808a | 298 | *errnop = errno; |
6259ec0d UD |
299 | } |
300 | if (retval == NSS_STATUS_NOTFOUND) | |
301 | *h_errnop = HOST_NOT_FOUND; | |
302 | return retval; | |
303 | } | |
304 | ||
ab9a9ff8 | 305 | const size_t linebuflen = buffer + buflen - data->linebuffer; |
a1ffb40e | 306 | if (__glibc_unlikely ((size_t) (len + 1) > linebuflen)) |
6259ec0d UD |
307 | { |
308 | free (result); | |
309 | *h_errnop = NETDB_INTERNAL; | |
d71b808a | 310 | *errnop = ERANGE; |
6259ec0d UD |
311 | return NSS_STATUS_TRYAGAIN; |
312 | } | |
313 | ||
ab9a9ff8 | 314 | char *p = strncpy (data->linebuffer, result, len); |
6259ec0d UD |
315 | data->linebuffer[len] = '\0'; |
316 | while (isspace (*p)) | |
317 | ++p; | |
318 | free (result); | |
319 | ||
ab9a9ff8 | 320 | int parse_res = parse_line (p, host, data, buflen, errnop, af, flags); |
6259ec0d | 321 | |
a1ffb40e | 322 | if (__glibc_unlikely (parse_res < 1 || host->h_addrtype != af)) |
6259ec0d | 323 | { |
60c96635 | 324 | if (parse_res == -1) |
6259ec0d UD |
325 | { |
326 | *h_errnop = NETDB_INTERNAL; | |
327 | return NSS_STATUS_TRYAGAIN; | |
328 | } | |
329 | else | |
330 | { | |
331 | *h_errnop = HOST_NOT_FOUND; | |
332 | return NSS_STATUS_NOTFOUND; | |
333 | } | |
334 | } | |
335 | ||
336 | *h_errnop = NETDB_SUCCESS; | |
337 | return NSS_STATUS_SUCCESS; | |
338 | } | |
339 | ||
1eb946b9 | 340 | |
1e275b9e UD |
341 | enum nss_status |
342 | _nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host, | |
343 | char *buffer, size_t buflen, int *errnop, | |
344 | int *h_errnop) | |
345 | { | |
1eb946b9 UD |
346 | if (af != AF_INET && af != AF_INET6) |
347 | { | |
348 | *h_errnop = HOST_NOT_FOUND; | |
349 | return NSS_STATUS_NOTFOUND; | |
350 | } | |
351 | ||
1e275b9e UD |
352 | return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop, |
353 | h_errnop, | |
b76e0659 | 354 | (res_use_inet6 () ? AI_V4MAPPED : 0)); |
1e275b9e UD |
355 | } |
356 | ||
1eb946b9 | 357 | |
0d8733c4 | 358 | enum nss_status |
d71b808a UD |
359 | _nss_nis_gethostbyname_r (const char *name, struct hostent *host, char *buffer, |
360 | size_t buflen, int *errnop, int *h_errnop) | |
0d8733c4 | 361 | { |
b76e0659 | 362 | if (res_use_inet6 ()) |
0d8733c4 UD |
363 | { |
364 | enum nss_status status; | |
365 | ||
1e275b9e UD |
366 | status = internal_gethostbyname2_r (name, AF_INET6, host, buffer, buflen, |
367 | errnop, h_errnop, AI_V4MAPPED); | |
0d8733c4 UD |
368 | if (status == NSS_STATUS_SUCCESS) |
369 | return status; | |
370 | } | |
371 | ||
1e275b9e UD |
372 | return internal_gethostbyname2_r (name, AF_INET, host, buffer, buflen, |
373 | errnop, h_errnop, 0); | |
0d8733c4 UD |
374 | } |
375 | ||
1eb946b9 | 376 | |
6259ec0d | 377 | enum nss_status |
9d4d69b8 | 378 | _nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, |
6259ec0d | 379 | struct hostent *host, char *buffer, size_t buflen, |
d71b808a | 380 | int *errnop, int *h_errnop) |
6259ec0d | 381 | { |
ab9a9ff8 | 382 | char *domain; |
a1ffb40e | 383 | if (__glibc_unlikely (yp_get_default_domain (&domain))) |
a334319f | 384 | return NSS_STATUS_UNAVAIL; |
0ecb606c | 385 | |
2f1687b9 UD |
386 | uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); |
387 | buffer += pad; | |
388 | ||
ab9a9ff8 | 389 | struct parser_data *data = (void *) buffer; |
a1ffb40e | 390 | if (__glibc_unlikely (buflen < sizeof *data + 1 + pad)) |
6259ec0d | 391 | { |
d71b808a | 392 | *errnop = ERANGE; |
6259ec0d UD |
393 | *h_errnop = NETDB_INTERNAL; |
394 | return NSS_STATUS_TRYAGAIN; | |
395 | } | |
2f1687b9 | 396 | buflen -= pad; |
6259ec0d | 397 | |
ab9a9ff8 | 398 | char *buf = inet_ntoa (*(const struct in_addr *) addr); |
6259ec0d | 399 | |
ab9a9ff8 UD |
400 | char *result; |
401 | int len; | |
402 | int yperr = yp_match (domain, "hosts.byaddr", buf, strlen (buf), &result, | |
403 | &len); | |
6259ec0d | 404 | |
a1ffb40e | 405 | if (__glibc_unlikely (yperr != YPERR_SUCCESS)) |
6259ec0d | 406 | { |
ab9a9ff8 UD |
407 | enum nss_status retval = yperr2nss (yperr); |
408 | ||
6259ec0d UD |
409 | if (retval == NSS_STATUS_TRYAGAIN) |
410 | { | |
411 | *h_errnop = TRY_AGAIN; | |
d71b808a | 412 | *errnop = errno; |
6259ec0d | 413 | } |
ab9a9ff8 | 414 | else if (retval == NSS_STATUS_NOTFOUND) |
34816665 UD |
415 | *h_errnop = HOST_NOT_FOUND; |
416 | ||
6259ec0d UD |
417 | return retval; |
418 | } | |
419 | ||
ab9a9ff8 | 420 | const size_t linebuflen = buffer + buflen - data->linebuffer; |
a1ffb40e | 421 | if (__glibc_unlikely ((size_t) (len + 1) > linebuflen)) |
6259ec0d UD |
422 | { |
423 | free (result); | |
d71b808a | 424 | *errnop = ERANGE; |
6259ec0d UD |
425 | *h_errnop = NETDB_INTERNAL; |
426 | return NSS_STATUS_TRYAGAIN; | |
427 | } | |
428 | ||
ab9a9ff8 | 429 | char *p = strncpy (data->linebuffer, result, len); |
6259ec0d UD |
430 | data->linebuffer[len] = '\0'; |
431 | while (isspace (*p)) | |
432 | ++p; | |
433 | free (result); | |
434 | ||
ab9a9ff8 | 435 | int parse_res = parse_line (p, host, data, buflen, errnop, af, |
b76e0659 | 436 | (res_use_inet6 () ? AI_V4MAPPED : 0)); |
a1ffb40e | 437 | if (__glibc_unlikely (parse_res < 1)) |
6259ec0d | 438 | { |
60c96635 | 439 | if (parse_res == -1) |
6259ec0d UD |
440 | { |
441 | *h_errnop = NETDB_INTERNAL; | |
442 | return NSS_STATUS_TRYAGAIN; | |
443 | } | |
444 | else | |
445 | { | |
446 | *h_errnop = HOST_NOT_FOUND; | |
447 | return NSS_STATUS_NOTFOUND; | |
448 | } | |
449 | } | |
450 | ||
451 | *h_errnop = NETDB_SUCCESS; | |
452 | return NSS_STATUS_SUCCESS; | |
453 | } | |
1e275b9e | 454 | |
1eb946b9 | 455 | |
1e275b9e | 456 | enum nss_status |
1eb946b9 UD |
457 | _nss_nis_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, |
458 | char *buffer, size_t buflen, int *errnop, | |
459 | int *herrnop, int32_t *ttlp) | |
1e275b9e | 460 | { |
1eb946b9 UD |
461 | char *domain; |
462 | if (yp_get_default_domain (&domain)) | |
a682a1bf UD |
463 | { |
464 | *herrnop = NO_DATA; | |
465 | return NSS_STATUS_UNAVAIL; | |
466 | } | |
1eb946b9 UD |
467 | |
468 | /* Convert name to lowercase. */ | |
469 | size_t namlen = strlen (name); | |
315eb1d8 AS |
470 | /* Limit name length to the maximum size of an RPC packet. */ |
471 | if (namlen > UDPMSGSIZE) | |
472 | { | |
473 | *errnop = ERANGE; | |
474 | return NSS_STATUS_UNAVAIL; | |
475 | } | |
476 | ||
1eb946b9 UD |
477 | char name2[namlen + 1]; |
478 | size_t i; | |
479 | ||
480 | for (i = 0; i < namlen; ++i) | |
481 | name2[i] = tolower (name[i]); | |
482 | name2[i] = '\0'; | |
483 | ||
484 | char *result; | |
485 | int len; | |
486 | int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len); | |
487 | ||
a1ffb40e | 488 | if (__glibc_unlikely (yperr != YPERR_SUCCESS)) |
1eb946b9 UD |
489 | { |
490 | enum nss_status retval = yperr2nss (yperr); | |
491 | ||
492 | if (retval == NSS_STATUS_TRYAGAIN) | |
493 | { | |
494 | *herrnop = TRY_AGAIN; | |
495 | *errnop = errno; | |
496 | } | |
497 | if (retval == NSS_STATUS_NOTFOUND) | |
498 | *herrnop = HOST_NOT_FOUND; | |
499 | return retval; | |
500 | } | |
501 | ||
1eb946b9 UD |
502 | if (*pat == NULL) |
503 | { | |
504 | uintptr_t pad = (-(uintptr_t) buffer | |
505 | % __alignof__ (struct gaih_addrtuple)); | |
506 | buffer += pad; | |
507 | buflen = buflen > pad ? buflen - pad : 0; | |
508 | ||
a1ffb40e | 509 | if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple))) |
1eb946b9 UD |
510 | { |
511 | erange: | |
512 | free (result); | |
513 | *errnop = ERANGE; | |
514 | *herrnop = NETDB_INTERNAL; | |
515 | return NSS_STATUS_TRYAGAIN; | |
516 | } | |
517 | ||
518 | *pat = (struct gaih_addrtuple *) buffer; | |
519 | buffer += sizeof (struct gaih_addrtuple); | |
520 | buflen -= sizeof (struct gaih_addrtuple); | |
521 | } | |
522 | ||
e87946cc UD |
523 | uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); |
524 | buffer += pad; | |
525 | ||
526 | struct parser_data *data = (void *) buffer; | |
527 | ||
a1ffb40e | 528 | if (__glibc_unlikely (buflen < sizeof *data + 1 + pad)) |
1eb946b9 | 529 | goto erange; |
e87946cc UD |
530 | buflen -= pad; |
531 | ||
532 | struct hostent host; | |
533 | int parse_res = parse_line (result, &host, data, buflen, errnop, AF_UNSPEC, | |
534 | 0); | |
a1ffb40e | 535 | if (__glibc_unlikely (parse_res < 1)) |
e87946cc UD |
536 | { |
537 | if (parse_res == -1) | |
538 | { | |
539 | *herrnop = NETDB_INTERNAL; | |
540 | return NSS_STATUS_TRYAGAIN; | |
541 | } | |
542 | else | |
543 | { | |
544 | *herrnop = HOST_NOT_FOUND; | |
545 | return NSS_STATUS_NOTFOUND; | |
546 | } | |
547 | } | |
548 | ||
549 | (*pat)->next = NULL; | |
1eb946b9 UD |
550 | (*pat)->family = host.h_addrtype; |
551 | memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length); | |
552 | (*pat)->scopeid = 0; | |
553 | assert (host.h_addr_list[1] == NULL); | |
554 | ||
e87946cc UD |
555 | /* Undo the alignment for parser_data. */ |
556 | buffer -= pad; | |
557 | buflen += pad; | |
558 | ||
559 | size_t h_name_len = strlen (host.h_name) + 1; | |
560 | if (h_name_len >= buflen) | |
561 | goto erange; | |
905ef0da | 562 | (*pat)->name = memcpy (buffer, host.h_name, h_name_len); |
e87946cc | 563 | |
1eb946b9 UD |
564 | free (result); |
565 | ||
566 | return NSS_STATUS_SUCCESS; | |
1e275b9e | 567 | } |