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