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