Update.
[platform/upstream/glibc.git] / nss / digits_dots.c
1 /* Copyright (C) 1997, 1999 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by H.J. Lu <hjl@gnu.ai.mit.edu>, 1997.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
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
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20   /*
21    * disallow names consisting only of digits/dots, unless
22    * they end in a dot.
23    */
24   if (isdigit (name[0]) || (isxdigit (name[0]) || name[0] == ':'))
25     {
26       const char *cp;
27       char *hostname;
28       typedef unsigned char host_addr_t [16];
29       host_addr_t *host_addr;
30       typedef char *host_addr_list_t [2];
31       host_addr_list_t *host_aliases;
32       host_addr_list_t *h_addr_ptrs;
33       size_t size_needed;
34       int addr_size;
35 #ifndef HAVE_AF
36       int af = -1;
37 #endif
38
39       switch (af)
40         {
41         case AF_INET:
42           addr_size = INADDRSZ;
43           break;
44
45         case AF_INET6:
46           addr_size = IN6ADDRSZ;
47           break;
48
49         default:
50           af = (_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET;
51           addr_size = af == AF_INET6 ? IN6ADDRSZ : INADDRSZ;
52           break;
53         }
54
55       size_needed = (sizeof (*host_addr)
56                      + sizeof (*host_aliases) + sizeof (*h_addr_ptrs)
57                      + strlen (name) + 1);
58
59 #ifdef HAVE_LOOKUP_BUFFER
60       if (buflen < size_needed)
61         {
62           __set_errno (ERANGE);
63           goto done;
64         }
65 #else
66       if (buffer_size < size_needed)
67         {
68           char *new_buf;
69           buffer_size = size_needed;
70           new_buf = realloc (buffer, buffer_size);
71
72           if (new_buf == NULL)
73             {
74               save = errno;
75               free (buffer);
76               buffer = NULL;
77               buffer_size = 0;
78               __set_errno (save);
79               result = (struct hostent *) NULL;
80               goto done;
81             }
82           buffer = new_buf;
83         }
84 #endif /* HAVE_LOOKUP_BUFFER */
85
86       memset (buffer, 0, size_needed);
87
88       host_addr = (host_addr_t *) buffer;
89       host_aliases = (host_addr_list_t *)
90         ((char *) host_addr + sizeof (*host_addr));
91       h_addr_ptrs = (host_addr_list_t *)
92         ((char *) host_aliases + sizeof (*host_aliases));
93       hostname = (char *) h_addr_ptrs + sizeof (*h_addr_ptrs);
94
95       if (isdigit (name[0]))
96         {
97           for (cp = name;; ++cp)
98             {
99               if (!*cp)
100                 {
101                   int ok;
102
103                   if (*--cp == '.')
104                     break;
105
106                   /* All-numeric, no dot at the end. Fake up a hostent as if
107                      we'd actually done a lookup.  What if someone types
108                      255.255.255.255?  The test below will succeed
109                      spuriously... ???  */
110                   if (af == AF_INET)
111                     ok = inet_aton (name, (struct in_addr *) host_addr);
112                   else
113                     {
114                       assert (af == AF_INET6);
115                       ok = (inet_pton (af, name, host_addr) > 0);
116                     }
117                   if (! ok)
118                     {
119                       __set_h_errno (HOST_NOT_FOUND);
120 #ifndef HAVE_LOOKUP_BUFFER
121                       result = (struct hostent *) NULL;
122 #endif
123                       goto done;
124                     }
125
126                   resbuf.h_name = strcpy (hostname, name);
127                   resbuf.h_aliases = *host_aliases;
128                   (*host_aliases)[0] = NULL;
129                   (*h_addr_ptrs)[0] = (char *)host_addr;
130                   (*h_addr_ptrs)[1] = (char *)0;
131                   resbuf.h_addr_list = *h_addr_ptrs;
132                   if (_res.options & RES_USE_INET6 && af == AF_INET)
133                     {
134                       /* We need to change the IP v4 address into the
135                          IP v6 address.  */
136                       char tmp[INADDRSZ], *p = (char *) host_addr;
137                       int i;
138
139                       /* Save a copy of the IP v4 address. */
140                       memcpy (tmp, host_addr, INADDRSZ);
141                       /* Mark this ipv6 addr as a mapped ipv4. */
142                       for (i = 0; i < 10; i++)
143                         *p++ = 0x00;
144                       *p++ = 0xff;
145                       *p++ = 0xff;
146                       /* Copy the IP v4 address. */
147                       memcpy (p, tmp, INADDRSZ);
148                       resbuf.h_addrtype = AF_INET6;
149                       resbuf.h_length = IN6ADDRSZ;
150                     }
151                   else
152                     {
153                       resbuf.h_addrtype = af;
154                       resbuf.h_length = addr_size;
155                     }
156                   __set_h_errno (NETDB_SUCCESS);
157 #ifdef HAVE_LOOKUP_BUFFER
158                   status = NSS_STATUS_SUCCESS;
159 #else
160                   result = &resbuf;
161 #endif
162                   goto done;
163                 }
164
165               if (!isdigit (*cp) && *cp != '.') break;
166             }
167         }
168
169       if ((isxdigit (name[0]) && strchr (name, ':') != NULL)
170           || name[0] == ':')
171         {
172           const char *cp;
173           char *hostname;
174           typedef unsigned char host_addr_t [16];
175           host_addr_t *host_addr;
176           typedef char *host_addr_list_t [2];
177           host_addr_list_t *host_aliases;
178           host_addr_list_t *h_addr_ptrs;
179           size_t size_needed;
180           int addr_size;
181 #ifndef HAVE_AF
182           int af = -1;
183 #endif
184
185           switch (af)
186             {
187             case AF_INET:
188               addr_size = INADDRSZ;
189               break;
190
191             case AF_INET6:
192               addr_size = IN6ADDRSZ;
193               break;
194
195             default:
196               af = (_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET;
197               addr_size = (af == AF_INET6 ) ? IN6ADDRSZ : INADDRSZ;
198               break;
199             }
200
201           size_needed = (sizeof (*host_addr)
202                          + sizeof (*host_aliases) + sizeof (*h_addr_ptrs)
203                          + strlen (name) + 1);
204
205 #ifdef HAVE_LOOKUP_BUFFER
206           if (buflen < size_needed)
207             {
208               __set_errno (ERANGE);
209               goto done;
210             }
211 #else
212           if (buffer_size < size_needed)
213             {
214               char *new_buf;
215               buffer_size = size_needed;
216               new_buf = realloc (buffer, buffer_size);
217
218               if (new_buf == NULL)
219                 {
220                   save = errno;
221                   free (buffer);
222                   __set_errno (save);
223                   buffer = NULL;
224                   buffer_size = 0;
225                   result = (struct hostent *) NULL;
226                   goto done;
227                 }
228               buffer = new_buf;
229             }
230 #endif /* HAVE_LOOKUP_BUFFER */
231
232           memset (buffer, 0, size_needed);
233
234           host_addr = (host_addr_t *) buffer;
235           host_aliases = (host_addr_list_t *)
236             ((char *) host_addr + sizeof (*host_addr));
237           h_addr_ptrs = (host_addr_list_t *)
238             ((char *) host_aliases + sizeof (*host_aliases));
239           hostname = (char *) h_addr_ptrs + sizeof (*h_addr_ptrs);
240
241           for (cp = name;; ++cp)
242             {
243               if (!*cp)
244                 {
245                   if (*--cp == '.')
246                     break;
247
248                   /* All-IPv6-legal, no dot at the end. Fake up a
249                      hostent as if we'd actually done a lookup.  */
250                   if (inet_pton (af, name, host_addr) <= 0)
251                     {
252                       __set_h_errno (HOST_NOT_FOUND);
253 #ifndef HAVE_LOOKUP_BUFFER
254                       result = (struct hostent *) NULL;
255 #endif
256                       goto done;
257                     }
258
259                   resbuf.h_name = strcpy (hostname, name);
260                   resbuf.h_aliases = *host_aliases;
261                   (*host_aliases)[0] = NULL;
262                   (*h_addr_ptrs)[0] = (char *) host_addr;
263                   (*h_addr_ptrs)[1] = (char *) 0;
264                   resbuf.h_addr_list = *h_addr_ptrs;
265                   resbuf.h_addrtype = af;
266                   resbuf.h_length = addr_size;
267                   __set_h_errno (NETDB_SUCCESS);
268 #ifdef HAVE_LOOKUP_BUFFER
269                   status = NSS_STATUS_SUCCESS;
270 #else
271                   result = &resbuf;
272 #endif
273                   goto done;
274                 }
275
276               if (!isxdigit (*cp) && *cp != ':' && *cp != '.') break;
277             }
278         }
279     }