update from main archive 970218
[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       struct hostent *host;
29       typedef unsigned char host_addr_t [16];
30       host_addr_t *host_addr;
31       typedef char *host_addr_list_t [2];
32       host_addr_list_t *host_aliases;
33       host_addr_list_t *h_addr_ptrs;
34       size_t size_needed;
35       int addr_size;
36 #ifndef HAVE_AF
37       int af = -1;
38 #endif
39
40       switch (af)
41         {
42         case AF_INET:
43           addr_size = INADDRSZ;
44           break;
45
46         case AF_INET6:
47           addr_size = IN6ADDRSZ;
48           break;
49
50         default:
51           af = (_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET;
52           addr_size = (af == AF_INET6 ) ? IN6ADDRSZ : INADDRSZ;
53           break;
54         }
55
56       size_needed = (sizeof (*host) + sizeof (*host_addr)
57                      + sizeof (*host_aliases) + sizeof (*h_addr_ptrs)
58                      + strlen (name) + 1);
59
60 #ifdef HAVE_LOOKUP_BUFFER
61       if (buflen < size_needed)
62         {
63           __set_errno (ERANGE);
64           goto done;
65         }
66 #else
67       if (buffer_size < size_needed)
68         {
69           char *new_buf;
70           buffer_size = size_needed;
71           new_buf = realloc (buffer, buffer_size);
72
73           if (new_buf == NULL)
74             {
75               save = errno;
76               free (buffer);
77               buffer = NULL;
78               buffer_size = 0;
79               __set_errno (save);
80               result = (struct hostent *) NULL;
81               goto done;
82             }
83           buffer = new_buf;
84         }
85 #endif /* HAVE_LOOKUP_BUFFER */
86
87       memset (buffer, 0, size_needed);
88
89       host = (struct hostent *) buffer;
90       host_addr = (host_addr_t *) ((char *) host + sizeof (*host));
91       host_aliases = (host_addr_list_t *)
92         ((char *) host_addr + sizeof (*host_addr));
93       h_addr_ptrs = (host_addr_list_t *)
94         ((char *) host_aliases + sizeof (*host_aliases));
95       hostname = (char *) h_addr_ptrs + sizeof (*h_addr_ptrs);
96
97       if (isdigit (name[0]))
98         {
99           for (cp = name;; ++cp)
100             {
101               if (!*cp)
102                 {
103                   if (*--cp == '.') break;
104
105         /* All-numeric, no dot at the end. Fake up a hostent as if
106            we'd actually done a lookup.  What if someone types
107            255.255.255.255?  The test below will succeed
108            spuriously... ???  */
109                   if (inet_pton (af, name, host_addr) <= 0)
110                     {
111                       __set_h_errno (HOST_NOT_FOUND);
112 #ifndef HAVE_LOOKUP_BUFFER
113                       result = (struct hostent *) NULL;
114 #endif
115                       goto done;
116                     }
117
118                   strcpy (hostname, name);
119                   host->h_name = hostname;
120                   host->h_aliases = *host_aliases;
121                   (*host_aliases)[0] = NULL;
122                   (*h_addr_ptrs)[0] = (char *)host_addr;
123                   (*h_addr_ptrs)[1] = (char *)0;
124                   host->h_addr_list = *h_addr_ptrs;
125                   if (_res.options & RES_USE_INET6 && af == AF_INET)
126                     {
127                       /* We need to change the IP v4 address into the
128                          IP v6 address.  */
129                       char tmp[INADDRSZ], *p = (char *) host_addr;
130                       int i;
131
132                       /* Save a copy of the IP v4 address. */
133                       memcpy (tmp, host_addr, INADDRSZ);
134                       /* Mark this ipv6 addr as a mapped ipv4. */
135                       for (i = 0; i < 10; i++)
136                         *p++ = 0x00;
137                       *p++ = 0xff;
138                       *p++ = 0xff;
139                       /* Copy the IP v4 address. */
140                       memcpy (p, tmp, INADDRSZ);
141                       host->h_addrtype = AF_INET6;
142                       host->h_length = IN6ADDRSZ;
143                     }
144                   else
145                     {
146                       host->h_addrtype = af;
147                       host->h_length = addr_size;
148                     }
149                   __set_h_errno (NETDB_SUCCESS);
150 #ifdef HAVE_LOOKUP_BUFFER
151                   status = NSS_STATUS_SUCCESS;
152 #else
153                   result = host;
154 #endif
155                   goto done;
156                 }
157
158               if (!isdigit (*cp) && *cp != '.') break;
159             }
160         }
161
162       if (isxdigit (name[0]) || name[0] == ':')
163         {
164           const char *cp;
165           char *hostname;
166           struct hostent *host;
167           typedef unsigned char host_addr_t [16];
168           host_addr_t *host_addr;
169           typedef char *host_addr_list_t [2];
170           host_addr_list_t *host_aliases;
171           host_addr_list_t *h_addr_ptrs;
172           size_t size_needed;
173           int addr_size;
174 #ifndef HAVE_AF
175           int af = -1;
176 #endif
177
178           switch (af)
179             {
180             case AF_INET:
181               addr_size = INADDRSZ;
182               break;
183
184             case AF_INET6:
185               addr_size = IN6ADDRSZ;
186               break;
187
188             default:
189               af = (_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET;
190               addr_size = (af == AF_INET6 ) ? IN6ADDRSZ : INADDRSZ;
191               break;
192             }
193
194           size_needed = (sizeof (*host) + sizeof (*host_addr)
195                          + sizeof (*host_aliases) + sizeof (*h_addr_ptrs)
196                          + strlen (name) + 1);
197
198 #ifdef HAVE_LOOKUP_BUFFER
199           if (buflen < size_needed)
200             {
201               __set_errno (ERANGE);
202               goto done;
203             }
204 #else
205           if (buffer_size < size_needed)
206             {
207               char *new_buf;
208               buffer_size = size_needed;
209               new_buf = realloc (buffer, buffer_size);
210
211               if (new_buf == NULL)
212                 {
213                   save = errno;
214                   free (buffer);
215                   __set_errno (save);
216                   buffer = NULL;
217                   buffer_size = 0;
218                   result = (struct hostent *) NULL;
219                   goto done;
220                 }
221               buffer = new_buf;
222             }
223 #endif /* HAVE_LOOKUP_BUFFER */
224
225           memset (buffer, 0, size_needed);
226
227           host = (struct hostent *) buffer;
228           host_addr = (host_addr_t *) ((char *) host + sizeof (*host));
229           host_aliases = (host_addr_list_t *)
230             ((char *) host_addr + sizeof (*host_addr));
231           h_addr_ptrs = (host_addr_list_t *)
232             ((char *) host_aliases + sizeof (*host_aliases));
233           hostname = (char *) h_addr_ptrs + sizeof (*h_addr_ptrs);
234
235           for (cp = name;; ++cp)
236             {
237               if (!*cp)
238                 {
239                   if (*--cp == '.')
240                     break;
241                   if (!strchr (name, ':'))
242                     break;
243
244                   /* All-IPv6-legal, no dot at the end. Fake up a
245                      hostent as if we'd actually done a lookup.  */
246                   if (inet_pton (af, name, host_addr) <= 0)
247                     {
248                       __set_h_errno (HOST_NOT_FOUND);
249 #ifndef HAVE_LOOKUP_BUFFER
250                       result = (struct hostent *) NULL;
251 #endif
252                       goto done;
253                     }
254
255                   strcpy (hostname, name);
256                   host->h_name = hostname;
257                   host->h_aliases = *host_aliases;
258                   (*host_aliases)[0] = NULL;
259                   (*h_addr_ptrs)[0] = (char *) host_addr;
260                   (*h_addr_ptrs)[1] = (char *) 0;
261                   host->h_addr_list = *h_addr_ptrs;
262                   host->h_addrtype = af;
263                   host->h_length = addr_size;
264                   __set_h_errno (NETDB_SUCCESS);
265 #ifdef HAVE_LOOKUP_BUFFER
266                   status = NSS_STATUS_SUCCESS;
267 #else
268                   result = host;
269 #endif
270                   goto done;
271                 }
272
273               if (!isxdigit (*cp) && *cp != ':' && *cp != '.') break;
274             }
275         }
276     }