]> git.ipfire.org Git - thirdparty/glibc.git/blame - inet/getnameinfo.c
_nss_compat_initgroups_dyn: Use struct scratch_buffer instead of extend_alloca
[thirdparty/glibc.git] / inet / getnameinfo.c
CommitLineData
1fb05e3d
UD
1/* The Inner Net License, Version 2.00
2
3 The author(s) grant permission for redistribution and use in source and
4binary forms, with or without modification, of the software and documentation
5provided that the following conditions are met:
6
70. If you receive a version of the software that is specifically labelled
8 as not being for redistribution (check the version message and/or README),
9 you are not permitted to redistribute that version of the software in any
10 way or form.
111. All terms of the all other applicable copyrights and licenses must be
12 followed.
132. Redistributions of source code must retain the authors' copyright
14 notice(s), this list of conditions, and the following disclaimer.
153. Redistributions in binary form must reproduce the authors' copyright
16 notice(s), this list of conditions, and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
aeb25823 184. [The copyright holder has authorized the removal of this clause.]
1fb05e3d
UD
195. Neither the name(s) of the author(s) nor the names of its contributors
20 may be used to endorse or promote products derived from this software
21 without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
24EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
27DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34 If these license terms cause you a real problem, contact the author. */
35
36/* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
37
c0bc5f7b 38#include <alloca.h>
1fb05e3d 39#include <errno.h>
c0bc5f7b 40#include <netdb.h>
965cba04 41#include <stddef.h>
6ac36398 42#include <stdlib.h>
1fb05e3d 43#include <stdio.h>
c0bc5f7b 44#include <string.h>
1fb05e3d 45#include <unistd.h>
e054f494 46#include <stdint.h>
5a97622d 47#include <arpa/inet.h>
c0bc5f7b
UD
48#include <net/if.h>
49#include <netinet/in.h>
50#include <sys/param.h>
51#include <sys/socket.h>
52#include <sys/types.h>
53#include <sys/un.h>
54#include <sys/utsname.h>
55#include <bits/libc-lock.h>
1fb05e3d 56
ab0fcbfa
UD
57#ifdef HAVE_LIBIDN
58# include <libidn/idna.h>
59extern int __idna_to_unicode_lzlz (const char *input, char **output,
60 int flags);
61#endif
62
1fb05e3d 63#ifndef min
cd6ede75 64# define min(x,y) (((x) > (y)) ? (y) : (x))
1fb05e3d
UD
65#endif /* min */
66
0d297437
UD
67libc_freeres_ptr (static char *domain);
68
1fb05e3d 69
40a55d20 70static char *
dfd2257a 71internal_function
cd6ede75 72nrl_domainname (void)
1fb05e3d 73{
390500b1 74 static int not_first;
1fb05e3d 75
3a07823a 76 if (! not_first)
cd6ede75
UD
77 {
78 __libc_lock_define_initialized (static, lock);
79 __libc_lock_lock (lock);
80
3a07823a 81 if (! not_first)
cd6ede75
UD
82 {
83 char *c;
84 struct hostent *h, th;
40a55d20 85 size_t tmpbuflen = 1024;
cd6ede75
UD
86 char *tmpbuf = alloca (tmpbuflen);
87 int herror;
88
390500b1 89 not_first = 1;
cd6ede75
UD
90
91 while (__gethostbyname_r ("localhost", &th, tmpbuf, tmpbuflen, &h,
92 &herror))
93 {
94 if (herror == NETDB_INTERNAL && errno == ERANGE)
218d76e0 95 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
cd6ede75
UD
96 else
97 break;
98 }
5a97622d 99
cd6ede75
UD
100 if (h && (c = strchr (h->h_name, '.')))
101 domain = __strdup (++c);
102 else
103 {
104 /* The name contains no domain information. Use the name
105 now to get more information. */
50304ef0 106 while (__gethostname (tmpbuf, tmpbuflen))
218d76e0 107 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
5a97622d 108
cd6ede75
UD
109 if ((c = strchr (tmpbuf, '.')))
110 domain = __strdup (++c);
111 else
112 {
113 /* We need to preserve the hostname. */
114 const char *hstname = strdupa (tmpbuf);
115
116 while (__gethostbyname_r (hstname, &th, tmpbuf, tmpbuflen,
117 &h, &herror))
118 {
119 if (herror == NETDB_INTERNAL && errno == ERANGE)
218d76e0
UD
120 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
121 2 * tmpbuflen);
cd6ede75
UD
122 else
123 break;
124 }
125
126 if (h && (c = strchr(h->h_name, '.')))
127 domain = __strdup (++c);
128 else
129 {
130 struct in_addr in_addr;
131
062a2a18 132 in_addr.s_addr = htonl (INADDR_LOOPBACK);
cd6ede75
UD
133
134 while (__gethostbyaddr_r ((const char *) &in_addr,
135 sizeof (struct in_addr),
136 AF_INET, &th, tmpbuf,
137 tmpbuflen, &h, &herror))
138 {
139 if (herror == NETDB_INTERNAL && errno == ERANGE)
218d76e0
UD
140 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
141 2 * tmpbuflen);
cd6ede75
UD
142 else
143 break;
144 }
145
146 if (h && (c = strchr (h->h_name, '.')))
147 domain = __strdup (++c);
148 }
149 }
5a97622d 150 }
5a97622d 151 }
1fb05e3d 152
cd6ede75 153 __libc_lock_unlock (lock);
1fb05e3d
UD
154 }
155
1fb05e3d
UD
156 return domain;
157};
158
cd6ede75
UD
159
160int
c7614ee9 161getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
ccd4b479 162 socklen_t hostlen, char *serv, socklen_t servlen,
e4ecafe0 163 int flags)
1fb05e3d
UD
164{
165 int serrno = errno;
5a97622d
UD
166 int tmpbuflen = 1024;
167 int herrno;
cd6ede75 168 char *tmpbuf = alloca (tmpbuflen);
5a97622d 169 struct hostent th;
c0bc5f7b 170 int ok = 0;
1fb05e3d 171
ab0fcbfa
UD
172 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
173#ifdef HAVE_LIBIDN
3a0e90bd 174 |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
ab0fcbfa
UD
175#endif
176 ))
85599e53
UD
177 return EAI_BADFLAGS;
178
922809a2 179 if (sa == NULL || addrlen < sizeof (sa_family_t))
85599e53 180 return EAI_FAMILY;
922809a2 181
d4f0720b
UD
182 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL)
183 return EAI_NONAME;
184
922809a2
UD
185 switch (sa->sa_family)
186 {
187 case AF_LOCAL:
965cba04 188 if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
85599e53 189 return EAI_FAMILY;
4fcddf8e
UD
190 break;
191 case AF_INET:
192 if (addrlen < sizeof (struct sockaddr_in))
85599e53 193 return EAI_FAMILY;
4fcddf8e
UD
194 break;
195 case AF_INET6:
196 if (addrlen < sizeof (struct sockaddr_in6))
85599e53 197 return EAI_FAMILY;
922809a2
UD
198 break;
199 default:
85599e53 200 return EAI_FAMILY;
922809a2 201 }
1fb05e3d 202
cd6ede75 203 if (host != NULL && hostlen > 0)
4fcddf8e 204 switch (sa->sa_family)
cd6ede75 205 {
1fb05e3d 206 case AF_INET:
1fb05e3d 207 case AF_INET6:
cd6ede75
UD
208 if (!(flags & NI_NUMERICHOST))
209 {
210 struct hostent *h = NULL;
6e310111
UD
211 if (sa->sa_family == AF_INET6)
212 {
213 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
214 sizeof(struct in6_addr),
215 AF_INET6, &th, tmpbuf, tmpbuflen,
216 &h, &herrno))
217 if (herrno == NETDB_INTERNAL && errno == ERANGE)
218 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
219 else
220 break;
221 }
222 else
223 {
224 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
225 sizeof(struct in_addr), AF_INET,
226 &th, tmpbuf, tmpbuflen,
227 &h, &herrno))
228 if (herrno == NETDB_INTERNAL && errno == ERANGE)
229 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
230 else
231 break;
232 }
233
cd6ede75
UD
234 if (h == NULL)
235 {
6e310111 236 if (herrno == NETDB_INTERNAL)
cd6ede75 237 {
6e310111
UD
238 __set_h_errno (herrno);
239 return EAI_SYSTEM;
5a97622d 240 }
6e310111 241 if (herrno == TRY_AGAIN)
cd6ede75 242 {
6e310111
UD
243 __set_h_errno (herrno);
244 return EAI_AGAIN;
cd6ede75 245 }
5a97622d 246 }
1fb05e3d 247
cd6ede75
UD
248 if (h)
249 {
85599e53 250 char *c;
104d0bd3 251 if ((flags & NI_NOFQDN)
85599e53
UD
252 && (c = nrl_domainname ())
253 && (c = strstr (h->h_name, c))
254 && (c != h->h_name) && (*(--c) == '.'))
ab0fcbfa
UD
255 /* Terminate the string after the prefix. */
256 *c = '\0';
257
258#ifdef HAVE_LIBIDN
259 /* If requested, convert from the IDN format. */
260 if (flags & NI_IDN)
cd6ede75 261 {
3a0e90bd
UD
262 int idn_flags = 0;
263 if (flags & NI_IDN_ALLOW_UNASSIGNED)
264 idn_flags |= IDNA_ALLOW_UNASSIGNED;
265 if (flags & NI_IDN_USE_STD3_ASCII_RULES)
266 idn_flags |= IDNA_USE_STD3_ASCII_RULES;
267
ab0fcbfa 268 char *out;
3a0e90bd
UD
269 int rc = __idna_to_unicode_lzlz (h->h_name, &out,
270 idn_flags);
ab0fcbfa
UD
271 if (rc != IDNA_SUCCESS)
272 {
273 if (rc == IDNA_MALLOC_ERROR)
274 return EAI_MEMORY;
275 if (rc == IDNA_DLOPEN_ERROR)
276 return EAI_SYSTEM;
277 return EAI_IDN_ENCODE;
278 }
279
280 if (out != h->h_name)
281 {
282 h->h_name = strdupa (out);
283 free (out);
284 }
cd6ede75 285 }
ab0fcbfa
UD
286#endif
287
288 size_t len = strlen (h->h_name) + 1;
289 if (len > hostlen)
290 return EAI_OVERFLOW;
291
292 memcpy (host, h->h_name, len);
293
294 ok = 1;
cd6ede75
UD
295 }
296 }
1fb05e3d 297
c0bc5f7b 298 if (!ok)
40a55d20 299 {
c0bc5f7b 300 if (flags & NI_NAMEREQD)
40a55d20
UD
301 {
302 __set_errno (serrno);
85599e53 303 return EAI_NONAME;
40a55d20 304 }
c0bc5f7b
UD
305 else
306 {
307 const char *c;
308 if (sa->sa_family == AF_INET6)
309 {
c3301189 310 const struct sockaddr_in6 *sin6p;
c0bc5f7b
UD
311 uint32_t scopeid;
312
c3301189
UD
313 sin6p = (const struct sockaddr_in6 *) sa;
314
c0bc5f7b 315 c = inet_ntop (AF_INET6,
c3301189 316 (const void *) &sin6p->sin6_addr, host, hostlen);
85599e53
UD
317 scopeid = sin6p->sin6_scope_id;
318 if (scopeid != 0)
c0bc5f7b
UD
319 {
320 /* Buffer is >= IFNAMSIZ+1. */
4fcddf8e 321 char scopebuf[IFNAMSIZ + 1];
85599e53 322 char *scopeptr;
c0bc5f7b 323 int ni_numericscope = 0;
85599e53
UD
324 size_t real_hostlen = __strnlen (host, hostlen);
325 size_t scopelen = 0;
326
327 scopebuf[0] = SCOPE_DELIMITER;
328 scopebuf[1] = '\0';
329 scopeptr = &scopebuf[1];
c0bc5f7b
UD
330
331 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
332 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
333 {
5804f16c 334 if (if_indextoname (scopeid, scopeptr) == NULL)
c0bc5f7b 335 ++ni_numericscope;
85599e53
UD
336 else
337 scopelen = strlen (scopebuf);
c0bc5f7b
UD
338 }
339 else
340 ++ni_numericscope;
341
342 if (ni_numericscope)
85599e53
UD
343 scopelen = 1 + __snprintf (scopeptr,
344 (scopebuf
345 + sizeof scopebuf
346 - scopeptr),
347 "%u", scopeid);
348
349 if (real_hostlen + scopelen + 1 > hostlen)
27deeafc
UD
350 /* Signal the buffer is too small. This is
351 what inet_ntop does. */
352 c = NULL;
353 else
354 memcpy (host + real_hostlen, scopebuf, scopelen + 1);
c0bc5f7b
UD
355 }
356 }
357 else
358 c = inet_ntop (AF_INET,
c3301189 359 (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
c0bc5f7b
UD
360 host, hostlen);
361 if (c == NULL)
27deeafc 362 return EAI_OVERFLOW;
c0bc5f7b
UD
363 }
364 ok = 1;
cd6ede75 365 }
1fb05e3d 366 break;
cd6ede75 367
1fb05e3d 368 case AF_LOCAL:
cd6ede75
UD
369 if (!(flags & NI_NUMERICHOST))
370 {
371 struct utsname utsname;
1fb05e3d 372
cd6ede75
UD
373 if (!uname (&utsname))
374 {
375 strncpy (host, utsname.nodename, hostlen);
376 break;
377 };
1fb05e3d 378 };
1fb05e3d
UD
379
380 if (flags & NI_NAMEREQD)
40a55d20
UD
381 {
382 __set_errno (serrno);
85599e53 383 return EAI_NONAME;
40a55d20 384 }
1fb05e3d 385
cd6ede75 386 strncpy (host, "localhost", hostlen);
1fb05e3d 387 break;
cd6ede75 388
1fb05e3d 389 default:
e4ecafe0 390 return EAI_FAMILY;
cd6ede75 391 }
1fb05e3d
UD
392
393 if (serv && (servlen > 0))
4fcddf8e 394 switch (sa->sa_family)
cd6ede75 395 {
1fb05e3d 396 case AF_INET:
1fb05e3d 397 case AF_INET6:
cd6ede75
UD
398 if (!(flags & NI_NUMERICSERV))
399 {
400 struct servent *s, ts;
0292b0dd
UD
401 int e;
402 while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
403 ((flags & NI_DGRAM)
404 ? "udp" : "tcp"),
405 &ts, tmpbuf, tmpbuflen, &s)))
cd6ede75 406 {
0292b0dd
UD
407 if (e == ERANGE)
408 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
cd6ede75 409 else
0292b0dd 410 break;
cd6ede75
UD
411 }
412 if (s)
413 {
40a55d20 414 strncpy (serv, s->s_name, servlen);
cd6ede75 415 break;
5a97622d 416 }
5a97622d 417 }
ab0fcbfa
UD
418
419 if (__snprintf (serv, servlen, "%d",
420 ntohs (((const struct sockaddr_in *) sa)->sin_port))
421 + 1 > servlen)
422 return EAI_OVERFLOW;
423
1fb05e3d 424 break;
cd6ede75 425
1fb05e3d 426 case AF_LOCAL:
c3301189 427 strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1fb05e3d 428 break;
cd6ede75
UD
429 }
430
1fb05e3d
UD
431 if (host && (hostlen > 0))
432 host[hostlen-1] = 0;
433 if (serv && (servlen > 0))
434 serv[servlen-1] = 0;
435 errno = serrno;
436 return 0;
40a55d20 437}
9b0b40d3 438libc_hidden_def (getnameinfo)