update from main archive 961211
[kopensolaris-gnu/glibc.git] / nis / nss_nis / nis-hosts.c
1 /* Copyright (C) 1996 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_gethostbyname_r (const char *name, 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)
301     {
302       if (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_gethostbyaddr_r (char *addr, int addrlen, int type,
320                           struct hostent *host, char *buffer, size_t buflen,
321                           int *h_errnop)
322 {
323   enum nss_status retval;
324   char *domain, *result, *p;
325   int len, parse_res;
326   char *buf;
327   struct parser_data *data = (void *) buffer;
328   size_t linebuflen = buffer + buflen - data->linebuffer;
329
330   if (yp_get_default_domain (&domain))
331     return NSS_STATUS_UNAVAIL;
332
333   if (buflen < sizeof *data + 1)
334     {
335       __set_errno (ERANGE);
336       *h_errnop = NETDB_INTERNAL;
337       return NSS_STATUS_TRYAGAIN;
338     }
339
340   buf = inet_ntoa (*(struct in_addr *) addr);
341
342   retval = yperr2nss (yp_match (domain, "hosts.byaddr", buf,
343                                 strlen (buf), &result, &len));
344
345   if (retval != NSS_STATUS_SUCCESS)
346     {
347       if (retval == NSS_STATUS_TRYAGAIN)
348         {
349           *h_errnop = TRY_AGAIN;
350           __set_errno (EAGAIN);
351         }
352       if (retval == NSS_STATUS_NOTFOUND)
353         *h_errnop = HOST_NOT_FOUND;
354       return retval;
355     }
356
357   if ((size_t) (len + 1) > linebuflen)
358     {
359       free (result);
360       __set_errno (ERANGE);
361       *h_errnop = NETDB_INTERNAL;
362       return NSS_STATUS_TRYAGAIN;
363     }
364
365   p = strncpy (data->linebuffer, result, len);
366   data->linebuffer[len] = '\0';
367   while (isspace (*p))
368     ++p;
369   free (result);
370
371   parse_res = parse_line (p, host, data, buflen);
372
373   if (!parse_res)
374     {
375       if (errno == ERANGE)
376         {
377           *h_errnop = NETDB_INTERNAL;
378           return NSS_STATUS_TRYAGAIN;
379         }
380       else
381         {
382           *h_errnop = HOST_NOT_FOUND;
383           return NSS_STATUS_NOTFOUND;
384         }
385     }
386
387   *h_errnop = NETDB_SUCCESS;
388   return NSS_STATUS_SUCCESS;
389 }