]> git.ipfire.org Git - thirdparty/glibc.git/blame - nis/nss_nisplus/nisplus-hosts.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / nis / nss_nisplus / nisplus-hosts.c
CommitLineData
b168057a 1/* Copyright (C) 1997-2015 Free Software Foundation, Inc.
e61abf83 2 This file is part of the GNU C Library.
1e275b9e 3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
e61abf83
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.
e61abf83
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.
e61abf83 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/>. */
e61abf83 18
1eb946b9 19#include <assert.h>
636e689e 20#include <atomic.h>
a334319f 21#include <ctype.h>
636e689e
UD
22#include <errno.h>
23#include <netdb.h>
24#include <nss.h>
e61abf83 25#include <string.h>
a334319f 26#include <arpa/inet.h>
636e689e 27#include <netinet/in.h>
a334319f 28#include <rpcsvc/nis.h>
636e689e 29#include <bits/libc-lock.h>
e61abf83
UD
30
31#include "nss-nisplus.h"
32
33__libc_lock_define_initialized (static, lock)
34
fc9f33e3
UD
35static nis_result *result;
36static nis_name tablename_val;
37static u_long tablename_len;
e61abf83 38
840094b5 39#define NISENTRYVAL(idx, col, res) \
a682a1bf 40 (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
e61abf83 41
840094b5 42#define NISENTRYLEN(idx, col, res) \
a682a1bf 43 (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
e61abf83
UD
44
45/* Get implementation for some internal functions. */
d71b808a 46#include <resolv/mapv4v6addr.h>
e61abf83 47
840094b5 48
e61abf83 49static int
900bec85 50_nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
1e275b9e
UD
51 char *buffer, size_t buflen, int *errnop,
52 int flags)
e61abf83 53{
7799b7b3 54 unsigned int i;
900bec85
UD
55 char *first_unused = buffer;
56 size_t room_left = buflen;
e61abf83
UD
57
58 if (result == NULL)
26dee9c4 59 return 0;
e61abf83 60
1eb946b9
UD
61 if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
62 || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
63 || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "hosts_tbl") != 0
64 || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4)
26dee9c4 65 return 0;
e61abf83 66
840094b5
UD
67 char *data = first_unused;
68
1eb946b9 69 if (room_left < (af != AF_INET || (flags & AI_V4MAPPED) != 0
840094b5 70 ? IN6ADDRSZ : INADDRSZ))
e61abf83 71 {
60c96635 72 no_more_room:
d71b808a 73 *errnop = ERANGE;
60c96635 74 return -1;
e61abf83 75 }
900bec85 76
1e275b9e 77 /* Parse address. */
1eb946b9
UD
78 if (af != AF_INET6
79 && inet_pton (AF_INET, NISENTRYVAL (0, 2, result), data) > 0)
900bec85 80 {
1eb946b9 81 assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC);
1e275b9e 82 if (flags & AI_V4MAPPED)
900bec85
UD
83 {
84 map_v4v6_address (data, data);
85 host->h_addrtype = AF_INET6;
86 host->h_length = IN6ADDRSZ;
87 }
88 else
89 {
90 host->h_addrtype = AF_INET;
91 host->h_length = INADDRSZ;
92 }
93 }
1eb946b9 94 else if (af != AF_INET
1e275b9e
UD
95 && inet_pton (AF_INET6, NISENTRYVAL (0, 2, result), data) > 0)
96 {
97 host->h_addrtype = AF_INET6;
98 host->h_length = IN6ADDRSZ;
99 }
100 else
101 /* Illegal address: ignore line. */
102 return 0;
103
840094b5
UD
104 first_unused += host->h_length;
105 room_left -= host->h_length;
e61abf83
UD
106
107 if (NISENTRYLEN (0, 0, result) + 1 > room_left)
60c96635 108 goto no_more_room;
8f2ece69 109
900bec85 110 host->h_name = first_unused;
840094b5
UD
111 first_unused = __stpncpy (first_unused, NISENTRYVAL (0, 0, result),
112 NISENTRYLEN (0, 0, result));
113 *first_unused++ = '\0';
840094b5 114
1eb946b9 115 room_left -= NISENTRYLEN (0, 0, result) + 1;
840094b5 116 char *line = first_unused;
1eb946b9
UD
117
118 /* When this is a call to gethostbyname4_r we do not need the aliases. */
119 if (af != AF_UNSPEC)
e61abf83 120 {
1eb946b9
UD
121 /* XXX Rewrite at some point to allocate the array first and then
122 copy the strings. It is wasteful to first concatenate the strings
123 to just split them again later. */
124 for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
900bec85 125 {
1eb946b9
UD
126 if (strcmp (NISENTRYVAL (i, 1, result), host->h_name) != 0)
127 {
128 if (NISENTRYLEN (i, 1, result) + 2 > room_left)
129 goto no_more_room;
130
131 *first_unused++ = ' ';
132 first_unused = __stpncpy (first_unused,
133 NISENTRYVAL (i, 1, result),
134 NISENTRYLEN (i, 1, result));
135 *first_unused = '\0';
136 room_left -= NISENTRYLEN (i, 1, result) + 1;
137 }
900bec85 138 }
1eb946b9 139 *first_unused++ = '\0';
900bec85 140 }
880f421f 141
900bec85
UD
142 /* Adjust the pointer so it is aligned for
143 storing pointers. */
840094b5
UD
144 size_t adjust = ((__alignof__ (char *)
145 - (first_unused - (char *) 0) % __alignof__ (char *))
146 % __alignof__ (char *));
147 if (room_left < adjust + 3 * sizeof (char *))
a334319f 148 goto no_more_room;
840094b5
UD
149 first_unused += adjust;
150 room_left -= adjust;
151 host->h_addr_list = (char **) first_unused;
8f2ece69 152
840094b5 153 room_left -= 3 * sizeof (char *);
900bec85
UD
154 host->h_addr_list[0] = data;
155 host->h_addr_list[1] = NULL;
156 host->h_aliases = &host->h_addr_list[2];
900bec85 157
1eb946b9
UD
158 /* When this is a call to gethostbyname4_r we do not need the aliases. */
159 if (af != AF_UNSPEC)
900bec85 160 {
1eb946b9
UD
161 i = 0;
162 while (*line != '\0')
163 {
164 /* Skip leading blanks. */
165 while (isspace (*line))
166 ++line;
900bec85 167
1eb946b9
UD
168 if (*line == '\0')
169 break;
900bec85 170
1eb946b9
UD
171 if (room_left < sizeof (char *))
172 goto no_more_room;
900bec85 173
1eb946b9
UD
174 room_left -= sizeof (char *);
175 host->h_aliases[i++] = line;
900bec85 176
1eb946b9
UD
177 while (*line != '\0' && *line != ' ')
178 ++line;
900bec85 179
1eb946b9
UD
180 if (*line == ' ')
181 *line++ = '\0';
182 }
840094b5 183
1eb946b9
UD
184 host->h_aliases[i] = NULL;
185 }
840094b5 186
900bec85 187 return 1;
e61abf83
UD
188}
189
840094b5 190
2d7da676 191static enum nss_status
d71b808a 192_nss_create_tablename (int *errnop)
2d7da676
UD
193{
194 if (tablename_val == NULL)
195 {
636e689e
UD
196 const char *local_dir = nis_local_directory ();
197 size_t local_dir_len = strlen (local_dir);
198 static const char prefix[] = "hosts.org_dir.";
2d7da676 199
636e689e 200 char *p = malloc (sizeof (prefix) + local_dir_len);
c8e82b4a 201 if (p == NULL)
d71b808a
UD
202 {
203 *errnop = errno;
204 return NSS_STATUS_TRYAGAIN;
205 }
636e689e
UD
206
207 memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
208
209 tablename_len = sizeof (prefix) - 1 + local_dir_len;
210
211 atomic_write_barrier ();
212
213 tablename_val = p;
2d7da676 214 }
636e689e 215
2d7da676
UD
216 return NSS_STATUS_SUCCESS;
217}
218
1eb946b9 219
e61abf83 220enum nss_status
51eecc4a 221_nss_nisplus_sethostent (int stayopen)
e61abf83 222{
2d7da676 223 enum nss_status status = NSS_STATUS_SUCCESS;
d71b808a 224 int err;
2d7da676 225
e61abf83
UD
226 __libc_lock_lock (lock);
227
636e689e
UD
228 if (result != NULL)
229 {
230 nis_freeresult (result);
231 result = NULL;
232 }
2d7da676
UD
233
234 if (tablename_val == NULL)
d71b808a 235 status = _nss_create_tablename (&err);
e61abf83
UD
236
237 __libc_lock_unlock (lock);
238
2d7da676 239 return status;
e61abf83
UD
240}
241
1eb946b9 242
e61abf83
UD
243enum nss_status
244_nss_nisplus_endhostent (void)
245{
246 __libc_lock_lock (lock);
247
636e689e
UD
248 if (result != NULL)
249 {
250 nis_freeresult (result);
251 result = NULL;
252 }
e61abf83
UD
253
254 __libc_lock_unlock (lock);
255
256 return NSS_STATUS_SUCCESS;
257}
258
1eb946b9 259
e61abf83
UD
260static enum nss_status
261internal_nisplus_gethostent_r (struct hostent *host, char *buffer,
d71b808a 262 size_t buflen, int *errnop, int *herrnop)
e61abf83
UD
263{
264 int parse_res;
265
266 /* Get the next entry until we found a correct one. */
267 do
268 {
60c96635
UD
269 nis_result *saved_res;
270
e61abf83
UD
271 if (result == NULL)
272 {
60c96635 273 saved_res = NULL;
2d7da676 274 if (tablename_val == NULL)
d71b808a
UD
275 {
276 enum nss_status status = _nss_create_tablename (errnop);
e61abf83 277
d71b808a
UD
278 if (status != NSS_STATUS_SUCCESS)
279 return status;
280 }
281
282 result = nis_first_entry (tablename_val);
487609e3
UD
283 if (result == NULL)
284 {
285 *errnop = errno;
286 return NSS_STATUS_TRYAGAIN;
287 }
e61abf83 288 if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
a682a1bf
UD
289 {
290 enum nss_status retval = niserr2nss (result->status);
291 if (retval == NSS_STATUS_TRYAGAIN)
292 {
293 *herrnop = NETDB_INTERNAL;
294 *errnop = errno;
295 }
296 return retval;
297 }
8f2ece69 298
e61abf83
UD
299 }
300 else
301 {
60c96635 302 saved_res = result;
487609e3
UD
303 result = nis_next_entry (tablename_val, &result->cookie);
304 if (result == NULL)
305 {
306 *errnop = errno;
307 return NSS_STATUS_TRYAGAIN;
308 }
e61abf83 309 if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
a682a1bf
UD
310 {
311 enum nss_status retval= niserr2nss (result->status);
e61abf83 312
60c96635
UD
313 nis_freeresult (result);
314 result = saved_res;
a682a1bf
UD
315 if (retval == NSS_STATUS_TRYAGAIN)
316 {
317 *herrnop = NETDB_INTERNAL;
d71b808a 318 *errnop = errno;
a682a1bf
UD
319 }
320 return retval;
321 }
e61abf83 322 }
8f2ece69 323
1e275b9e
UD
324 if (_res.options & RES_USE_INET6)
325 parse_res = _nss_nisplus_parse_hostent (result, AF_INET6, host, buffer,
326 buflen, errnop, AI_V4MAPPED);
327 else
328 parse_res = _nss_nisplus_parse_hostent (result, AF_INET, host, buffer,
329 buflen, errnop, 0);
330
ac9f45cf 331 if (parse_res == -1)
a682a1bf 332 {
60c96635
UD
333 nis_freeresult (result);
334 result = saved_res;
a682a1bf 335 *herrnop = NETDB_INTERNAL;
d71b808a 336 *errnop = ERANGE;
a682a1bf
UD
337 return NSS_STATUS_TRYAGAIN;
338 }
60c96635
UD
339 if (saved_res != NULL)
340 nis_freeresult (saved_res);
8f2ece69 341
e61abf83 342 } while (!parse_res);
8f2ece69 343
e61abf83
UD
344 return NSS_STATUS_SUCCESS;
345}
346
1eb946b9 347
e61abf83
UD
348enum nss_status
349_nss_nisplus_gethostent_r (struct hostent *result, char *buffer,
d71b808a 350 size_t buflen, int *errnop, int *herrnop)
e61abf83
UD
351{
352 int status;
353
354 __libc_lock_lock (lock);
355
d71b808a
UD
356 status = internal_nisplus_gethostent_r (result, buffer, buflen, errnop,
357 herrnop);
e61abf83
UD
358
359 __libc_lock_unlock (lock);
360
361 return status;
362}
363
1eb946b9
UD
364
365static enum nss_status
366get_tablename (int *herrnop)
367{
368 __libc_lock_lock (lock);
369
370 enum nss_status status = _nss_create_tablename (herrnop);
371
372 __libc_lock_unlock (lock);
373
374 if (status != NSS_STATUS_SUCCESS)
375 *herrnop = NETDB_INTERNAL;
376
377 return status;
378}
379
380
1e275b9e
UD
381static enum nss_status
382internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
383 char *buffer, size_t buflen, int *errnop,
384 int *herrnop, int flags)
e61abf83 385{
2d7da676 386 if (tablename_val == NULL)
d71b808a 387 {
1eb946b9 388 enum nss_status status = get_tablename (herrnop);
d71b808a 389 if (status != NSS_STATUS_SUCCESS)
1eb946b9 390 return status;
d71b808a 391 }
2d7da676 392
e61abf83
UD
393 if (name == NULL)
394 {
d71b808a 395 *errnop = EINVAL;
e61abf83
UD
396 *herrnop = NETDB_INTERNAL;
397 return NSS_STATUS_NOTFOUND;
398 }
e61abf83 399
636e689e
UD
400 char buf[strlen (name) + 10 + tablename_len];
401 int olderr = errno;
8f2ece69 402
636e689e
UD
403 /* Search at first in the alias list, and use the correct name
404 for the next search. */
405 snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
1eb946b9 406 nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
a334319f 407
636e689e
UD
408 if (result != NULL)
409 {
636e689e
UD
410 /* If we did not find it, try it as original name. But if the
411 database is correct, we should find it in the first case, too. */
1eb946b9
UD
412 char *bufptr = buf;
413 size_t buflen = sizeof (buf);
414
415 if ((result->status == NIS_SUCCESS || result->status == NIS_S_SUCCESS)
416 && __type_of (result->objects.objects_val) == NIS_ENTRY_OBJ
417 && strcmp (result->objects.objects_val->EN_data.en_type,
418 "hosts_tbl") == 0
419 && result->objects.objects_val->EN_data.en_cols.en_cols_len >= 3)
901956a5 420 {
636e689e 421 /* We need to allocate a new buffer since there is no
1eb946b9
UD
422 guarantee the returned alias name has a length limit. */
423 name = NISENTRYVAL(0, 0, result);
424 size_t buflen = strlen (name) + 10 + tablename_len;
636e689e 425 bufptr = alloca (buflen);
901956a5 426 }
e61abf83 427
1eb946b9
UD
428 snprintf (bufptr, buflen, "[cname=%s],%s", name, tablename_val);
429
e61abf83 430 nis_freeresult (result);
636e689e
UD
431 result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
432 }
8f2ece69 433
636e689e
UD
434 if (result == NULL)
435 {
436 *errnop = ENOMEM;
a682a1bf 437 *herrnop = NETDB_INTERNAL;
636e689e
UD
438 return NSS_STATUS_TRYAGAIN;
439 }
e61abf83 440
1eb946b9 441 int retval = niserr2nss (result->status);
a1ffb40e 442 if (__glibc_unlikely (retval != NSS_STATUS_SUCCESS))
636e689e
UD
443 {
444 if (retval == NSS_STATUS_TRYAGAIN)
d71b808a 445 {
636e689e 446 *errnop = errno;
a682a1bf 447 *herrnop = TRY_AGAIN;
d71b808a 448 }
e61abf83 449 else
a682a1bf
UD
450 {
451 __set_errno (olderr);
452 *herrnop = NETDB_INTERNAL;
453 }
636e689e
UD
454 nis_freeresult (result);
455 return retval;
e61abf83 456 }
636e689e 457
1eb946b9
UD
458 int parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer,
459 buflen, errnop, flags);
636e689e
UD
460
461 nis_freeresult (result);
462
463 if (parse_res > 0)
464 return NSS_STATUS_SUCCESS;
465
466 *herrnop = NETDB_INTERNAL;
467 if (parse_res == -1)
468 {
469 *errnop = ERANGE;
470 return NSS_STATUS_TRYAGAIN;
471 }
472
473 __set_errno (olderr);
474 return NSS_STATUS_NOTFOUND;
e61abf83
UD
475}
476
1eb946b9 477
1e275b9e
UD
478enum nss_status
479_nss_nisplus_gethostbyname2_r (const char *name, int af, struct hostent *host,
480 char *buffer, size_t buflen, int *errnop,
481 int *herrnop)
482{
1eb946b9
UD
483 if (af != AF_INET && af != AF_INET6)
484 {
485 *herrnop = HOST_NOT_FOUND;
486 return NSS_STATUS_NOTFOUND;
487 }
488
1e275b9e
UD
489 return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop,
490 herrnop,
491 ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
492}
493
1eb946b9 494
e61abf83
UD
495enum nss_status
496_nss_nisplus_gethostbyname_r (const char *name, struct hostent *host,
d71b808a
UD
497 char *buffer, size_t buflen, int *errnop,
498 int *h_errnop)
e61abf83
UD
499{
500 if (_res.options & RES_USE_INET6)
501 {
502 enum nss_status status;
503
1e275b9e
UD
504 status = internal_gethostbyname2_r (name, AF_INET6, host, buffer,
505 buflen, errnop, h_errnop,
506 AI_V4MAPPED);
e61abf83 507 if (status == NSS_STATUS_SUCCESS)
a682a1bf 508 return status;
e61abf83
UD
509 }
510
1e275b9e
UD
511 return internal_gethostbyname2_r (name, AF_INET, host, buffer,
512 buflen, errnop, h_errnop, 0);
e61abf83
UD
513}
514
1eb946b9 515
e61abf83 516enum nss_status
9d4d69b8 517_nss_nisplus_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
900bec85 518 struct hostent *host, char *buffer,
d71b808a 519 size_t buflen, int *errnop, int *herrnop)
e61abf83 520{
2d7da676 521 if (tablename_val == NULL)
d71b808a 522 {
1eb946b9 523 enum nss_status status = get_tablename (herrnop);
d71b808a
UD
524 if (status != NSS_STATUS_SUCCESS)
525 return status;
526 }
2d7da676 527
e61abf83
UD
528 if (addr == NULL)
529 return NSS_STATUS_NOTFOUND;
8f2ece69 530
636e689e
UD
531 char buf[24 + tablename_len];
532 int retval, parse_res;
533 int olderr = errno;
0ecb606c 534
636e689e
UD
535 snprintf (buf, sizeof (buf), "[addr=%s],%s",
536 inet_ntoa (*(const struct in_addr *) addr), tablename_val);
537 nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
0ecb606c 538
636e689e
UD
539 if (result == NULL)
540 {
541 __set_errno (ENOMEM);
542 return NSS_STATUS_TRYAGAIN;
543 }
0ecb606c 544
636e689e 545 retval = niserr2nss (result->status);
a1ffb40e 546 if (__glibc_unlikely (retval != NSS_STATUS_SUCCESS))
636e689e
UD
547 {
548 if (retval == NSS_STATUS_TRYAGAIN)
a334319f 549 {
636e689e
UD
550 *errnop = errno;
551 *herrnop = NETDB_INTERNAL;
a334319f
UD
552 }
553 else
636e689e
UD
554 __set_errno (olderr);
555 nis_freeresult (result);
556 return retval;
557 }
558
559 parse_res = _nss_nisplus_parse_hostent (result, af, host,
560 buffer, buflen, errnop,
561 ((_res.options & RES_USE_INET6)
562 ? AI_V4MAPPED : 0));
563 nis_freeresult (result);
564
565 if (parse_res > 0)
566 return NSS_STATUS_SUCCESS;
567
568 *herrnop = NETDB_INTERNAL;
569 if (parse_res == -1)
570 {
571 *errnop = ERANGE;
572 return NSS_STATUS_TRYAGAIN;
0ecb606c 573 }
636e689e
UD
574
575 __set_errno (olderr);
576 return NSS_STATUS_NOTFOUND;
e61abf83 577}
1eb946b9
UD
578
579
580enum nss_status
581_nss_nisplus_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
582 char *buffer, size_t buflen, int *errnop,
583 int *herrnop, int32_t *ttlp)
584{
585 struct hostent host;
586
587 enum nss_status status = internal_gethostbyname2_r (name, AF_UNSPEC, &host,
588 buffer, buflen,
589 errnop, herrnop, 0);
a1ffb40e 590 if (__glibc_likely (status == NSS_STATUS_SUCCESS))
1eb946b9
UD
591 {
592 if (*pat == NULL)
593 {
594 uintptr_t pad = (-(uintptr_t) buffer
595 % __alignof__ (struct gaih_addrtuple));
596 buffer += pad;
597 buflen = buflen > pad ? buflen - pad : 0;
598
a1ffb40e 599 if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple)))
1eb946b9
UD
600 {
601 free (result);
602 *errnop = ERANGE;
603 *herrnop = NETDB_INTERNAL;
604 return NSS_STATUS_TRYAGAIN;
605 }
606 }
607
608 (*pat)->next = NULL;
609 (*pat)->name = host.h_name;
610 (*pat)->family = host.h_addrtype;
611
612 memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length);
613 (*pat)->scopeid = 0;
614 assert (host.h_addr_list[1] == NULL);
615 }
616
617 return status;
618}