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