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