Same changes as in nss/nss_files/files-hosts.c (Always use inet_pton).
[kopensolaris-gnu/glibc.git] / nis / nss_nis / nis-hosts.c
1 /* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
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 #include <nss.h>
21 #include <ctype.h>
22 #include <netdb.h>
23 #include <string.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <resolv.h>
27 #include <libc-lock.h>
28 #include <rpcsvc/yp.h>
29 #include <rpcsvc/ypclnt.h>
30
31 #include "nss-nis.h"
32
33 /* Get implementation for some internal functions. */
34 #include <resolv/mapv4v6addr.h>
35
36 #define ENTNAME         hostent
37 #define DATABASE        "hosts"
38 #define NEED_H_ERRNO
39
40 #define ENTDATA hostent_data
41 struct hostent_data
42   {
43     unsigned char host_addr[16];        /* IPv4 or IPv6 address.  */
44     char *h_addr_ptrs[2];       /* Points to that and null terminator.  */
45   };
46
47 #define TRAILING_LIST_MEMBER            h_aliases
48 #define TRAILING_LIST_SEPARATOR_P       isspace
49 #include <nss/nss_files/files-parse.c>
50 LINE_PARSER
51 ("#",
52  {
53    char *addr;
54
55    STRING_FIELD (addr, isspace, 1);
56
57    /* Parse address.  */
58    if (inet_pton (AF_INET6, p, entdata->host_addr) > 0)
59      {
60        result->h_addrtype = AF_INET6;
61        result->h_length = IN6ADDRSZ;
62      }
63    else
64      if (inet_pton (AF_INET, addr, entdata->host_addr) > 0)
65        {
66          if (_res.options & RES_USE_INET6)
67            {
68              map_v4v6_address ((char *) entdata->host_addr,
69                                (char *) entdata->host_addr);
70              result->h_addrtype = AF_INET6;
71              result->h_length = IN6ADDRSZ;
72            }
73          else
74            {
75              result->h_addrtype = AF_INET;
76              result->h_length = INADDRSZ;
77            }
78        }
79      else
80        /* Illegal address: ignore line.  */
81        return 0;
82
83    /* Store a pointer to the address in the expected form.  */
84    entdata->h_addr_ptrs[0] = entdata->host_addr;
85    entdata->h_addr_ptrs[1] = NULL;
86    result->h_addr_list = entdata->h_addr_ptrs;
87
88    STRING_FIELD (result->h_name, isspace, 1);
89  }
90 )
91
92 __libc_lock_define_initialized (static, lock)
93
94 static bool_t new_start = 1;
95 static char *oldkey = NULL;
96 static int oldkeylen = 0;
97
98 enum nss_status
99 _nss_nis_sethostent (void)
100 {
101   __libc_lock_lock (lock);
102
103   new_start = 1;
104   if (oldkey != NULL)
105     {
106       free (oldkey);
107       oldkey = NULL;
108       oldkeylen = 0;
109     }
110
111   __libc_lock_unlock (lock);
112
113   return NSS_STATUS_SUCCESS;
114 }
115
116 enum nss_status
117 _nss_nis_endhostent (void)
118 {
119   __libc_lock_lock (lock);
120
121   new_start = 1;
122   if (oldkey != NULL)
123     {
124       free (oldkey);
125       oldkey = NULL;
126       oldkeylen = 0;
127     }
128
129   __libc_lock_unlock (lock);
130
131   return NSS_STATUS_SUCCESS;
132 }
133
134 static enum nss_status
135 internal_nis_gethostent_r (struct hostent *host, char *buffer,
136                            size_t buflen, int *h_errnop)
137 {
138   char *domain;
139   char *result;
140   int len, parse_res;
141   char *outkey;
142   int keylen;
143   struct parser_data *data = (void *) buffer;
144   size_t linebuflen = buffer + buflen - data->linebuffer;
145
146   if (yp_get_default_domain (&domain))
147     return NSS_STATUS_UNAVAIL;
148
149   if (buflen < sizeof *data + 1)
150     {
151       __set_errno (ERANGE);
152       *h_errnop = NETDB_INTERNAL;
153       return NSS_STATUS_TRYAGAIN;
154     }
155
156   /* Get the next entry until we found a correct one. */
157   do
158     {
159       enum nss_status retval;
160       char *p;
161
162       if (new_start)
163         retval = yperr2nss (yp_first (domain, "hosts.byname",
164                                       &outkey, &keylen, &result, &len));
165       else
166         retval = yperr2nss ( yp_next (domain, "hosts.byname",
167                                       oldkey, oldkeylen,
168                                       &outkey, &keylen, &result, &len));
169
170       if (retval != NSS_STATUS_SUCCESS)
171         {
172           switch (retval)
173             {
174             case NSS_STATUS_TRYAGAIN:
175               __set_errno (EAGAIN);
176               *h_errnop = TRY_AGAIN;
177               break;
178             case NSS_STATUS_NOTFOUND:
179               *h_errnop = HOST_NOT_FOUND;
180               break;
181             default:
182               *h_errnop = NO_RECOVERY;
183               break;
184             }
185           return retval;
186         }
187
188       if ((size_t) (len + 1) > linebuflen)
189         {
190           free (result);
191           *h_errnop = NETDB_INTERNAL;
192           __set_errno (ERANGE);
193           return NSS_STATUS_TRYAGAIN;
194         }
195
196       p = strncpy (data->linebuffer, result, len);
197       data->linebuffer[len] = '\0';
198       while (isspace (*p))
199         ++p;
200       free (result);
201
202       parse_res = parse_line (p, host, data, buflen);
203       if (!parse_res && errno == ERANGE)
204         {
205           *h_errnop = NETDB_INTERNAL;;
206           return NSS_STATUS_TRYAGAIN;
207         }
208       free (oldkey);
209       oldkey = outkey;
210       oldkeylen = keylen;
211       new_start = 0;
212     }
213   while (!parse_res);
214
215   *h_errnop = NETDB_SUCCESS;
216   return NSS_STATUS_SUCCESS;
217 }
218
219 int
220 _nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen,
221                        int *h_errnop)
222 {
223   int status;
224
225   __libc_lock_lock (lock);
226
227   status = internal_nis_gethostent_r (host, buffer, buflen, h_errnop);
228
229   __libc_lock_unlock (lock);
230
231   return status;
232 }
233
234 enum nss_status
235 _nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host,
236                           char *buffer, size_t buflen, int *h_errnop)
237 {
238   enum nss_status retval;
239   char *domain, *result, *p;
240   int len, parse_res;
241   struct parser_data *data = (void *) buffer;
242   size_t linebuflen = buffer + buflen - data->linebuffer;
243
244   if (name == NULL)
245     {
246       __set_errno (EINVAL);
247       return NSS_STATUS_UNAVAIL;
248     }
249
250   if (yp_get_default_domain (&domain))
251     return NSS_STATUS_UNAVAIL;
252
253   if (buflen < sizeof *data + 1)
254     {
255       *h_errnop = NETDB_INTERNAL;
256       __set_errno (ERANGE);
257       return NSS_STATUS_TRYAGAIN;
258     }
259   retval = yperr2nss (yp_match (domain, "hosts.byname", name,
260                                 strlen (name), &result, &len));
261
262   if (retval != NSS_STATUS_SUCCESS)
263     {
264       if (retval == NSS_STATUS_TRYAGAIN)
265         {
266           *h_errnop = TRY_AGAIN;
267           __set_errno (EAGAIN);
268         }
269       if (retval == NSS_STATUS_NOTFOUND)
270         *h_errnop = HOST_NOT_FOUND;
271       return retval;
272     }
273
274   if ((size_t) (len + 1) > linebuflen)
275     {
276       free (result);
277       *h_errnop = NETDB_INTERNAL;
278       __set_errno (ERANGE);
279       return NSS_STATUS_TRYAGAIN;
280     }
281
282   p = strncpy (data->linebuffer, result, len);
283   data->linebuffer[len] = '\0';
284   while (isspace (*p))
285     ++p;
286   free (result);
287
288   parse_res = parse_line (p, host, data, buflen);
289
290   if (!parse_res || host->h_addrtype != af)
291     {
292       if (!parse_res && errno == ERANGE)
293         {
294           *h_errnop = NETDB_INTERNAL;
295           return NSS_STATUS_TRYAGAIN;
296         }
297       else
298         {
299           *h_errnop = HOST_NOT_FOUND;
300           return NSS_STATUS_NOTFOUND;
301         }
302     }
303
304   *h_errnop = NETDB_SUCCESS;
305   return NSS_STATUS_SUCCESS;
306 }
307
308 enum nss_status
309 _nss_nis_gethostbyname_r (const char *name, struct hostent *host,
310                           char *buffer, size_t buflen, int *h_errnop)
311 {
312   if (_res.options & RES_USE_INET6)
313     {
314       enum nss_status status;
315
316       status = _nss_nis_gethostbyname2_r (name, AF_INET6, host, buffer, buflen,
317                                           h_errnop);
318       if (status == NSS_STATUS_SUCCESS)
319         return status;
320     }
321
322   return _nss_nis_gethostbyname2_r (name, AF_INET, host, buffer, buflen,
323                                     h_errnop);
324 }
325
326 enum nss_status
327 _nss_nis_gethostbyaddr_r (char *addr, int addrlen, int type,
328                           struct hostent *host, char *buffer, size_t buflen,
329                           int *h_errnop)
330 {
331   enum nss_status retval;
332   char *domain, *result, *p;
333   int len, parse_res;
334   char *buf;
335   struct parser_data *data = (void *) buffer;
336   size_t linebuflen = buffer + buflen - data->linebuffer;
337
338   if (yp_get_default_domain (&domain))
339     return NSS_STATUS_UNAVAIL;
340
341   if (buflen < sizeof *data + 1)
342     {
343       __set_errno (ERANGE);
344       *h_errnop = NETDB_INTERNAL;
345       return NSS_STATUS_TRYAGAIN;
346     }
347
348   buf = inet_ntoa (*(struct in_addr *) addr);
349
350   retval = yperr2nss (yp_match (domain, "hosts.byaddr", buf,
351                                 strlen (buf), &result, &len));
352
353   if (retval != NSS_STATUS_SUCCESS)
354     {
355       if (retval == NSS_STATUS_TRYAGAIN)
356         {
357           *h_errnop = TRY_AGAIN;
358           __set_errno (EAGAIN);
359         }
360       if (retval == NSS_STATUS_NOTFOUND)
361         *h_errnop = HOST_NOT_FOUND;
362       return retval;
363     }
364
365   if ((size_t) (len + 1) > linebuflen)
366     {
367       free (result);
368       __set_errno (ERANGE);
369       *h_errnop = NETDB_INTERNAL;
370       return NSS_STATUS_TRYAGAIN;
371     }
372
373   p = strncpy (data->linebuffer, result, len);
374   data->linebuffer[len] = '\0';
375   while (isspace (*p))
376     ++p;
377   free (result);
378
379   parse_res = parse_line (p, host, data, buflen);
380
381   if (!parse_res)
382     {
383       if (errno == ERANGE)
384         {
385           *h_errnop = NETDB_INTERNAL;
386           return NSS_STATUS_TRYAGAIN;
387         }
388       else
389         {
390           *h_errnop = HOST_NOT_FOUND;
391           return NSS_STATUS_NOTFOUND;
392         }
393     }
394
395   *h_errnop = NETDB_SUCCESS;
396   return NSS_STATUS_SUCCESS;
397 }