Update.
[kopensolaris-gnu/glibc.git] / nss / digits_dots.c
1 /* Copyright (C) 1997 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                   if (*--cp == '.') break;
102
103         /* All-numeric, no dot at the end. Fake up a hostent as if
104            we'd actually done a lookup.  What if someone types
105            255.255.255.255?  The test below will succeed
106            spuriously... ???  */
107                   if (inet_pton (af, name, host_addr) <= 0)
108                     {
109                       __set_h_errno (HOST_NOT_FOUND);
110 #ifndef HAVE_LOOKUP_BUFFER
111                       result = (struct hostent *) NULL;
112 #endif
113                       goto done;
114                     }
115
116                   resbuf.h_name = strcpy (hostname, name);
117                   resbuf.h_aliases = *host_aliases;
118                   (*host_aliases)[0] = NULL;
119                   (*h_addr_ptrs)[0] = (char *)host_addr;
120                   (*h_addr_ptrs)[1] = (char *)0;
121                   resbuf.h_addr_list = *h_addr_ptrs;
122                   if (_res.options & RES_USE_INET6 && af == AF_INET)
123                     {
124                       /* We need to change the IP v4 address into the
125                          IP v6 address.  */
126                       char tmp[INADDRSZ], *p = (char *) host_addr;
127                       int i;
128
129                       /* Save a copy of the IP v4 address. */
130                       memcpy (tmp, host_addr, INADDRSZ);
131                       /* Mark this ipv6 addr as a mapped ipv4. */
132                       for (i = 0; i < 10; i++)
133                         *p++ = 0x00;
134                       *p++ = 0xff;
135                       *p++ = 0xff;
136                       /* Copy the IP v4 address. */
137                       memcpy (p, tmp, INADDRSZ);
138                       resbuf.h_addrtype = AF_INET6;
139                       resbuf.h_length = IN6ADDRSZ;
140                     }
141                   else
142                     {
143                       resbuf.h_addrtype = af;
144                       resbuf.h_length = addr_size;
145                     }
146                   __set_h_errno (NETDB_SUCCESS);
147 #ifdef HAVE_LOOKUP_BUFFER
148                   status = NSS_STATUS_SUCCESS;
149 #else
150                   result = &resbuf;
151 #endif
152                   goto done;
153                 }
154
155               if (!isdigit (*cp) && *cp != '.') break;
156             }
157         }
158
159       if ((isxdigit (name[0]) && strchr (name, ':') != NULL)
160           || name[0] == ':')
161         {
162           const char *cp;
163           char *hostname;
164           typedef unsigned char host_addr_t [16];
165           host_addr_t *host_addr;
166           typedef char *host_addr_list_t [2];
167           host_addr_list_t *host_aliases;
168           host_addr_list_t *h_addr_ptrs;
169           size_t size_needed;
170           int addr_size;
171 #ifndef HAVE_AF
172           int af = -1;
173 #endif
174
175           switch (af)
176             {
177             case AF_INET:
178               addr_size = INADDRSZ;
179               break;
180
181             case AF_INET6:
182               addr_size = IN6ADDRSZ;
183               break;
184
185             default:
186               af = (_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET;
187               addr_size = (af == AF_INET6 ) ? IN6ADDRSZ : INADDRSZ;
188               break;
189             }
190
191           size_needed = (sizeof (*host_addr)
192                          + sizeof (*host_aliases) + sizeof (*h_addr_ptrs)
193                          + strlen (name) + 1);
194
195 #ifdef HAVE_LOOKUP_BUFFER
196           if (buflen < size_needed)
197             {
198               __set_errno (ERANGE);
199               goto done;
200             }
201 #else
202           if (buffer_size < size_needed)
203             {
204               char *new_buf;
205               buffer_size = size_needed;
206               new_buf = realloc (buffer, buffer_size);
207
208               if (new_buf == NULL)
209                 {
210                   save = errno;
211                   free (buffer);
212                   __set_errno (save);
213                   buffer = NULL;
214                   buffer_size = 0;
215                   result = (struct hostent *) NULL;
216                   goto done;
217                 }
218               buffer = new_buf;
219             }
220 #endif /* HAVE_LOOKUP_BUFFER */
221
222           memset (buffer, 0, size_needed);
223
224           host_addr = (host_addr_t *) buffer;
225           host_aliases = (host_addr_list_t *)
226             ((char *) host_addr + sizeof (*host_addr));
227           h_addr_ptrs = (host_addr_list_t *)
228             ((char *) host_aliases + sizeof (*host_aliases));
229           hostname = (char *) h_addr_ptrs + sizeof (*h_addr_ptrs);
230
231           for (cp = name;; ++cp)
232             {
233               if (!*cp)
234                 {
235                   if (*--cp == '.')
236                     break;
237
238                   /* All-IPv6-legal, no dot at the end. Fake up a
239                      hostent as if we'd actually done a lookup.  */
240                   if (inet_pton (af, name, host_addr) <= 0)
241                     {
242                       __set_h_errno (HOST_NOT_FOUND);
243 #ifndef HAVE_LOOKUP_BUFFER
244                       result = (struct hostent *) NULL;
245 #endif
246                       goto done;
247                     }
248
249                   resbuf.h_name = strcpy (hostname, name);
250                   resbuf.h_aliases = *host_aliases;
251                   (*host_aliases)[0] = NULL;
252                   (*h_addr_ptrs)[0] = (char *) host_addr;
253                   (*h_addr_ptrs)[1] = (char *) 0;
254                   resbuf.h_addr_list = *h_addr_ptrs;
255                   resbuf.h_addrtype = af;
256                   resbuf.h_length = addr_size;
257                   __set_h_errno (NETDB_SUCCESS);
258 #ifdef HAVE_LOOKUP_BUFFER
259                   status = NSS_STATUS_SUCCESS;
260 #else
261                   result = &resbuf;
262 #endif
263                   goto done;
264                 }
265
266               if (!isxdigit (*cp) && *cp != ':' && *cp != '.') break;
267             }
268         }
269     }