(_nss_nis_gethostbyname2_r): Correct last change.
[kopensolaris-gnu/glibc.git] / nis / nss_nis / nis-hosts.c
1 /* Copyright (C) 1996, 1997, 1998 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 <bits/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, addr, 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 *errnop, 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       *errnop = 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               *errnop = errno;
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           *errnop = 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, errnop);
203       if (parse_res == -1)
204         {
205           free (outkey);
206           *h_errnop = NETDB_INTERNAL;
207           *errnop = ERANGE;
208           return NSS_STATUS_TRYAGAIN;
209         }
210       free (oldkey);
211       oldkey = outkey;
212       oldkeylen = keylen;
213       new_start = 0;
214     }
215   while (!parse_res);
216
217   *h_errnop = NETDB_SUCCESS;
218   return NSS_STATUS_SUCCESS;
219 }
220
221 int
222 _nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen,
223                        int *errnop, int *h_errnop)
224 {
225   int status;
226
227   __libc_lock_lock (lock);
228
229   status = internal_nis_gethostent_r (host, buffer, buflen, errnop, h_errnop);
230
231   __libc_lock_unlock (lock);
232
233   return status;
234 }
235
236 enum nss_status
237 _nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host,
238                            char *buffer, size_t buflen, int *errnop,
239                            int *h_errnop)
240 {
241   enum nss_status retval;
242   char *domain, *result, *p;
243   int len, parse_res;
244   struct parser_data *data = (void *) buffer;
245   size_t linebuflen = buffer + buflen - data->linebuffer;
246
247   if (name == NULL)
248     {
249       *errnop = EINVAL;
250       return NSS_STATUS_UNAVAIL;
251     }
252
253   if (yp_get_default_domain (&domain))
254     return NSS_STATUS_UNAVAIL;
255
256   if (buflen < sizeof *data + 1)
257     {
258       *h_errnop = NETDB_INTERNAL;
259       *errnop = ERANGE;
260       return NSS_STATUS_TRYAGAIN;
261     }
262   else
263     {
264       /* Convert name to lowercase.  */
265       size_t namlen = strlen (name);
266       char name2[namlen + 1];
267       int i;
268
269       for (i = 0; i < namlen; ++i)
270         name2[i] = tolower (name[i]);
271       name2[i] = '\0';
272
273       retval = yperr2nss (yp_match (domain, "hosts.byname", name2,
274                                     namlen, &result, &len));
275
276     }
277
278   if (retval != NSS_STATUS_SUCCESS)
279     {
280       if (retval == NSS_STATUS_TRYAGAIN)
281         {
282           *h_errnop = TRY_AGAIN;
283           *errnop = errno;
284         }
285       if (retval == NSS_STATUS_NOTFOUND)
286         *h_errnop = HOST_NOT_FOUND;
287       return retval;
288     }
289
290   if ((size_t) (len + 1) > linebuflen)
291     {
292       free (result);
293       *h_errnop = NETDB_INTERNAL;
294       *errnop = ERANGE;
295       return NSS_STATUS_TRYAGAIN;
296     }
297
298   p = strncpy (data->linebuffer, result, len);
299   data->linebuffer[len] = '\0';
300   while (isspace (*p))
301     ++p;
302   free (result);
303
304   parse_res = parse_line (p, host, data, buflen, errnop);
305
306   if (parse_res < 1 || host->h_addrtype != af)
307     {
308       if (parse_res == -1)
309         {
310           *h_errnop = NETDB_INTERNAL;
311           return NSS_STATUS_TRYAGAIN;
312         }
313       else
314         {
315           *h_errnop = HOST_NOT_FOUND;
316           return NSS_STATUS_NOTFOUND;
317         }
318     }
319
320   *h_errnop = NETDB_SUCCESS;
321   return NSS_STATUS_SUCCESS;
322 }
323
324 enum nss_status
325 _nss_nis_gethostbyname_r (const char *name, struct hostent *host, char *buffer,
326                           size_t buflen, int *errnop, int *h_errnop)
327 {
328   if (_res.options & RES_USE_INET6)
329     {
330       enum nss_status status;
331
332       status = _nss_nis_gethostbyname2_r (name, AF_INET6, host, buffer, buflen,
333                                           errnop, h_errnop);
334       if (status == NSS_STATUS_SUCCESS)
335         return status;
336     }
337
338   return _nss_nis_gethostbyname2_r (name, AF_INET, host, buffer, buflen,
339                                     errnop, h_errnop);
340 }
341
342 enum nss_status
343 _nss_nis_gethostbyaddr_r (char *addr, int addrlen, int type,
344                           struct hostent *host, char *buffer, size_t buflen,
345                           int *errnop, int *h_errnop)
346 {
347   enum nss_status retval;
348   char *domain, *result, *p;
349   int len, parse_res;
350   char *buf;
351   struct parser_data *data = (void *) buffer;
352   size_t linebuflen = buffer + buflen - data->linebuffer;
353
354   if (yp_get_default_domain (&domain))
355     return NSS_STATUS_UNAVAIL;
356
357   if (buflen < sizeof *data + 1)
358     {
359       *errnop = ERANGE;
360       *h_errnop = NETDB_INTERNAL;
361       return NSS_STATUS_TRYAGAIN;
362     }
363
364   buf = inet_ntoa (*(struct in_addr *) addr);
365
366   retval = yperr2nss (yp_match (domain, "hosts.byaddr", buf,
367                                 strlen (buf), &result, &len));
368
369   if (retval != NSS_STATUS_SUCCESS)
370     {
371       if (retval == NSS_STATUS_TRYAGAIN)
372         {
373           *h_errnop = TRY_AGAIN;
374           *errnop = errno;
375         }
376       if (retval == NSS_STATUS_NOTFOUND)
377         *h_errnop = HOST_NOT_FOUND;
378       return retval;
379     }
380
381   if ((size_t) (len + 1) > linebuflen)
382     {
383       free (result);
384       *errnop = ERANGE;
385       *h_errnop = NETDB_INTERNAL;
386       return NSS_STATUS_TRYAGAIN;
387     }
388
389   p = strncpy (data->linebuffer, result, len);
390   data->linebuffer[len] = '\0';
391   while (isspace (*p))
392     ++p;
393   free (result);
394
395   parse_res = parse_line (p, host, data, buflen, errnop);
396   if (parse_res < 1)
397     {
398       if (parse_res == -1)
399         {
400           *h_errnop = NETDB_INTERNAL;
401           return NSS_STATUS_TRYAGAIN;
402         }
403       else
404         {
405           *h_errnop = HOST_NOT_FOUND;
406           return NSS_STATUS_NOTFOUND;
407         }
408     }
409
410   *h_errnop = NETDB_SUCCESS;
411   return NSS_STATUS_SUCCESS;
412 }