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